Comparing version 0.0.3-12 to 0.0.3-13
{ | ||
"name": "derw", | ||
"version": "0.0.3-12", | ||
"version": "0.0.3-13", | ||
"description": "An Elm-inspired language that transpiles to TypeScript", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -5,2 +5,6 @@ # derw | ||
Homepage: https://derw-lang.github.io/ | ||
Follow Derw on Twitter: https://twitter.com/derwlang | ||
# Install | ||
@@ -48,3 +52,2 @@ | ||
--names : Check for missing names out of scope | ||
--format : Format the files given in-place | ||
--quiet : Keep it short and sweet | ||
@@ -134,5 +137,12 @@ -h, --help : This help text | ||
user: User | ||
user = { name: string } | ||
user = { name: "Noah" } | ||
``` | ||
- [x] Object literals updates | ||
```elm | ||
user: User | ||
user = { ...noah, name: "Noah" } | ||
``` | ||
- [x] Imports | ||
@@ -367,2 +377,7 @@ | ||
- [x] An automatic formatter with no options | ||
``` | ||
derw format | ||
``` | ||
- [ ] A standard library | ||
@@ -410,2 +425,8 @@ - [x] Support for [Coed](https://github.com/eeue56/coed) | ||
- [x] Install a package | ||
``` | ||
derw install --name derw-lang/stdlib --version main | ||
``` | ||
- [x] An info command to find out stats about modules | ||
@@ -412,0 +433,0 @@ |
@@ -5,2 +5,3 @@ #!/usr/bin/env ts-node | ||
import { compileFiles } from "./cli/compile"; | ||
import { format } from "./cli/format"; | ||
import { info } from "./cli/info"; | ||
@@ -20,3 +21,4 @@ import { init } from "./cli/init"; | ||
| "repl" | ||
| "bundle"; | ||
| "bundle" | ||
| "format"; | ||
@@ -43,2 +45,4 @@ function parseCliCommand(): Result<string, CliCommand> { | ||
return Ok("bundle"); | ||
case "format": | ||
return Ok("format"); | ||
default: { | ||
@@ -99,2 +103,6 @@ return Err(`Unknown command \`${process.argv[2]}\``); | ||
} | ||
case "format": { | ||
await format(isInPackageDirectory, argv); | ||
return 0; | ||
} | ||
} | ||
@@ -101,0 +109,0 @@ } |
@@ -17,3 +17,3 @@ import { | ||
import { promises } from "fs"; | ||
import { readdir, writeFile } from "fs/promises"; | ||
import { writeFile } from "fs/promises"; | ||
import path from "path"; | ||
@@ -27,3 +27,3 @@ import * as util from "util"; | ||
import { Block, ContextModule, contextModuleToModule, Import } from "../types"; | ||
import { ensureDirectoryExists, fileExists } from "./utils"; | ||
import { ensureDirectoryExists, fileExists, getDerwFiles } from "./utils"; | ||
@@ -46,3 +46,2 @@ const compileParser = parser([ | ||
longFlag("run", "Should be run via ts-node/node", empty()), | ||
longFlag("format", "Format the files given in-place", empty()), | ||
longFlag("names", "Check for missing names out of scope", empty()), | ||
@@ -87,23 +86,2 @@ longFlag("watch", "Watch the files for changes", empty()), | ||
async function getDerwFiles(dir: string): Promise<string[]> { | ||
let files: string[] = [ ]; | ||
for (const file of await readdir(dir, { withFileTypes: true })) { | ||
if (file.isFile()) { | ||
if (file.name.endsWith("derw")) { | ||
files.push(path.join(dir, file.name)); | ||
} | ||
} else if (file.isDirectory()) { | ||
if (file.name === "node_modules") { | ||
} else { | ||
files = files.concat( | ||
await getDerwFiles(path.join(dir, file.name)) | ||
); | ||
} | ||
} | ||
} | ||
return files; | ||
} | ||
function filterBodyForName(module: ContextModule, name: string): Block[] { | ||
@@ -196,4 +174,2 @@ const blocks = [ ]; | ||
const isFormat = program.flags.format.isPresent; | ||
const outputDir = program.flags.output.isPresent | ||
@@ -208,5 +184,3 @@ ? (program.flags.output.arguments as Ok<string>).value | ||
const target = isFormat | ||
? "derw" | ||
: program.flags.target.isPresent | ||
const target = program.flags.target.isPresent | ||
? (program.flags.target.arguments as Ok<Target>).value | ||
@@ -213,0 +187,0 @@ : "ts"; |
@@ -18,3 +18,3 @@ import { | ||
"dir", | ||
"name of a directory to get info about e.g stdlib", | ||
"name of a directory to use as package name e.g stdlib", | ||
string() | ||
@@ -59,7 +59,8 @@ ), | ||
async function appendGitIgnore(): Promise<void> { | ||
async function appendGitIgnore(dir: string): Promise<void> { | ||
let gitIgnore = ""; | ||
const gitIgnorePath = path.join(dir, ".gitignore"); | ||
try { | ||
gitIgnore = await (await readFile(".gitignore")).toString(); | ||
gitIgnore = await (await readFile(gitIgnorePath)).toString(); | ||
} catch (e) {} | ||
@@ -77,3 +78,3 @@ | ||
await writeFile(".gitignore", gitIgnore); | ||
await writeFile(gitIgnorePath, gitIgnore); | ||
} | ||
@@ -111,3 +112,3 @@ | ||
await copyTSconfig(dir); | ||
await appendGitIgnore(); | ||
await appendGitIgnore(dir); | ||
await ensureDirectoryExists(path.join(dir, "src")); | ||
@@ -114,0 +115,0 @@ |
@@ -26,3 +26,3 @@ import { | ||
longFlag("name", "name of the package e.g derw-lang/stdlib", string()), | ||
longFlag("version", "name of the package e.g derw-lang/stdlib", string()), | ||
longFlag("version", "name of the package e.g main or master", string()), | ||
longFlag("quiet", "Keep it short and sweet", empty()), | ||
@@ -29,0 +29,0 @@ bothFlag("h", "help", "This help text", empty()), |
import { promises } from "fs"; | ||
import { readdir } from "fs/promises"; | ||
import path from "path"; | ||
@@ -22,1 +24,22 @@ export async function fileExists(name: string): Promise<boolean> { | ||
} | ||
export async function getDerwFiles(dir: string): Promise<string[]> { | ||
let files: string[] = [ ]; | ||
for (const file of await readdir(dir, { withFileTypes: true })) { | ||
if (file.isFile()) { | ||
if (file.name.endsWith("derw")) { | ||
files.push(path.join(dir, file.name)); | ||
} | ||
} else if (file.isDirectory()) { | ||
if (file.name === "node_modules") { | ||
} else { | ||
files = files.concat( | ||
await getDerwFiles(path.join(dir, file.name)) | ||
); | ||
} | ||
} | ||
} | ||
return files; | ||
} |
@@ -99,3 +99,16 @@ import { | ||
function generateObjectLiteralWithBase(literal: ObjectLiteral): string { | ||
const base = (literal.base as Value).body; | ||
let fields = literal.fields.map(generateField).join(",\n "); | ||
if (literal.fields.length === 1) return `{ ${base}, ${fields} }`; | ||
return `{ | ||
${base}, | ||
${fields} | ||
}`; | ||
} | ||
function generateObjectLiteral(literal: ObjectLiteral): string { | ||
if (literal.base) return generateObjectLiteralWithBase(literal); | ||
let fields = literal.fields.map(generateField).join(",\n "); | ||
@@ -314,4 +327,33 @@ | ||
if (functionCall.args.length === 0) return `${functionCall.name}()`; | ||
const right = functionCall.args.map(generateExpression).join(" "); | ||
let output: string[] = [ ]; | ||
for (const arg of functionCall.args) { | ||
switch (arg.kind) { | ||
case "Constructor": | ||
case "FunctionCall": { | ||
output.push("(" + generateExpression(arg) + ")"); | ||
break; | ||
} | ||
case "ModuleReference": { | ||
switch (arg.value.kind) { | ||
case "Constructor": | ||
case "FunctionCall": { | ||
output.push("(" + generateExpression(arg) + ")"); | ||
break; | ||
} | ||
default: { | ||
output.push(generateExpression(arg)); | ||
break; | ||
} | ||
} | ||
break; | ||
} | ||
default: { | ||
output.push(generateExpression(arg)); | ||
} | ||
} | ||
} | ||
const right = output.join(" "); | ||
return `${functionCall.name} ${right}`; | ||
@@ -318,0 +360,0 @@ } |
@@ -99,3 +99,18 @@ import { | ||
function generateObjectLiteralWithBase(literal: ObjectLiteral): string { | ||
const base = (literal.base as Value).body; | ||
const baseWithoutDots = base.split("...")[1]; | ||
let fields = literal.fields.map(generateField).join(",\n "); | ||
if (literal.fields.length === 1) | ||
return `{ ${baseWithoutDots} | ${fields} }`; | ||
return `{ | ||
${baseWithoutDots} | | ||
${fields} | ||
}`; | ||
} | ||
function generateObjectLiteral(literal: ObjectLiteral): string { | ||
if (literal.base) return generateObjectLiteralWithBase(literal); | ||
let fields = literal.fields.map(generateField).join(",\n "); | ||
@@ -345,4 +360,32 @@ | ||
if (functionCall.args.length === 0) return `${functionCall.name}`; | ||
const right = functionCall.args.map(generateExpression).join(" "); | ||
let output: string[] = [ ]; | ||
for (const arg of functionCall.args) { | ||
switch (arg.kind) { | ||
case "Constructor": | ||
case "FunctionCall": { | ||
output.push("(" + generateExpression(arg) + ")"); | ||
break; | ||
} | ||
case "ModuleReference": { | ||
switch (arg.value.kind) { | ||
case "Constructor": | ||
case "FunctionCall": { | ||
output.push("(" + generateExpression(arg) + ")"); | ||
break; | ||
} | ||
default: { | ||
output.push(generateExpression(arg)); | ||
break; | ||
} | ||
} | ||
break; | ||
} | ||
default: { | ||
output.push(generateExpression(arg)); | ||
} | ||
} | ||
} | ||
const right = output.join(" "); | ||
return `${functionCall.name} ${right}`; | ||
@@ -349,0 +392,0 @@ } |
@@ -84,3 +84,18 @@ import { | ||
function generateObjectLiteralWithBase(literal: ObjectLiteral): string { | ||
const base = (literal.base as Value).body; | ||
if (literal.fields.length === 0) return `{ ${base} }`; | ||
let fields = literal.fields.map(generateField).join(",\n "); | ||
if (literal.fields.length === 1) return `{ ${base}, ${fields} }`; | ||
return `{ | ||
${base}, | ||
${fields} | ||
}`; | ||
} | ||
function generateObjectLiteral(literal: ObjectLiteral): string { | ||
if (literal.base !== null) return generateObjectLiteralWithBase(literal); | ||
if (literal.fields.length === 0) return `{ }`; | ||
@@ -87,0 +102,0 @@ |
@@ -1,2 +0,2 @@ | ||
import { Err, Ok, Result } from "@eeue56/ts-core/build/main/lib/result"; | ||
import { Ok, Result } from "@eeue56/ts-core/build/main/lib/result"; | ||
@@ -720,2 +720,8 @@ type Empty = { | ||
export type TypeTokenRaw = | ||
| IdentifierToken | ||
| ArrowToken | ||
| OpenBracketToken | ||
| CloseBracketToken; | ||
export type TypeToken = | ||
@@ -734,46 +740,39 @@ | IdentifierToken | ||
): Result<string, RootTypeTokens[]> { | ||
const typeTokens: RootTypeTokens[] = [ ]; | ||
let currentToken: TypeToken[] = [ ]; | ||
let innerToken: TypeToken[] = [ ]; | ||
let isInInner = false; | ||
let isInFunction = false; | ||
let wasInFunction = false; | ||
let bracketDepth = 0; | ||
let rootTypeTokens: RootTypeTokens[] = [ ]; | ||
let currentBuffer: TypeTokenRaw[] = [ ]; | ||
let indent = 0; | ||
let index = 0; | ||
for (const token of tokens) { | ||
switch (token.kind) { | ||
case "WhitespaceToken": { | ||
case "OpenBracketToken": { | ||
if (indent > 0 || currentBuffer.length > 0) | ||
currentBuffer.push(token); | ||
indent++; | ||
break; | ||
} | ||
case "OpenBracketToken": { | ||
bracketDepth++; | ||
if (currentToken.length === 0) { | ||
isInFunction = true; | ||
} else { | ||
isInInner = true; | ||
} | ||
case "CloseBracketToken": { | ||
if (indent > 0) currentBuffer.push(token); | ||
indent--; | ||
break; | ||
} | ||
case "CloseBracketToken": { | ||
bracketDepth--; | ||
if (isInFunction) { | ||
if (bracketDepth === 0) { | ||
typeTokens.push(FunctionTypeToken(currentToken)); | ||
currentToken = [ ]; | ||
isInFunction = false; | ||
wasInFunction = true; | ||
case "ArrowToken": { | ||
if (indent === 0) { | ||
const isFunction = currentBuffer.find( | ||
(t) => t.kind === "ArrowToken" | ||
); | ||
const tokenized = tokenizeType(currentBuffer); | ||
if (tokenized.kind === "err") return tokenized; | ||
if (isFunction) { | ||
rootTypeTokens.push(FunctionTypeToken(tokenized.value)); | ||
} else { | ||
currentToken.push(token); | ||
for (const t of tokenized.value) { | ||
rootTypeTokens.push(t); | ||
} | ||
} | ||
} else if (isInInner) { | ||
if (bracketDepth === 0) { | ||
currentToken.push(BaseTypeToken(innerToken)); | ||
innerToken = [ ]; | ||
isInInner = false; | ||
} else { | ||
} | ||
currentBuffer = [ ]; | ||
} else { | ||
currentToken.push(token); | ||
currentBuffer.push(token); | ||
} | ||
@@ -784,36 +783,94 @@ break; | ||
case "IdentifierToken": { | ||
if (isInInner) { | ||
innerToken.push(token); | ||
} else { | ||
currentToken.push(token); | ||
} | ||
currentBuffer.push(token); | ||
break; | ||
} | ||
default: | ||
continue; | ||
} | ||
} | ||
case "ArrowToken": { | ||
if (isInFunction) { | ||
currentToken.push(token); | ||
} else if (wasInFunction) { | ||
wasInFunction = false; | ||
} else { | ||
typeTokens.push(BaseTypeToken(currentToken)); | ||
currentToken = [ ]; | ||
if (currentBuffer.length > 0) { | ||
if (currentBuffer.find((t) => t.kind === "OpenBracketToken")) { | ||
const isFunction = currentBuffer.find( | ||
(t) => t.kind === "ArrowToken" | ||
); | ||
let tokenized: Result<string, RootTypeTokens[]> = Ok([ ]); | ||
if (currentBuffer[0].kind === "IdentifierToken" && !isFunction) { | ||
let depth = 0; | ||
let inner: any[] = [ ]; | ||
let collectedInners = [ ]; | ||
for (const t of currentBuffer.slice(1)) { | ||
switch (t.kind) { | ||
case "OpenBracketToken": { | ||
if (depth > 0) inner.push(t); | ||
depth++; | ||
break; | ||
} | ||
case "CloseBracketToken": { | ||
if (depth > 1) inner.push(t); | ||
depth--; | ||
if (depth === 0) { | ||
const innerTokenized = tokenizeType(inner); | ||
if (innerTokenized.kind === "err") | ||
return innerTokenized; | ||
collectedInners.push(innerTokenized.value); | ||
inner = [ ]; | ||
} | ||
break; | ||
} | ||
case "IdentifierToken": { | ||
if (depth === 0) { | ||
} else { | ||
inner.push(t); | ||
} | ||
break; | ||
} | ||
case "ArrowToken": { | ||
if (depth === 0) { | ||
} else { | ||
inner.push(t); | ||
} | ||
} | ||
} | ||
let flattened: RootTypeTokens[] = [ ]; | ||
for (const collected of collectedInners) { | ||
flattened = flattened.concat(collected); | ||
} | ||
tokenized = Ok([ | ||
BaseTypeToken([ currentBuffer[0], ...flattened ]), | ||
]); | ||
} | ||
break; | ||
} else { | ||
tokenized = tokenizeType(currentBuffer); | ||
} | ||
if (tokenized.kind === "err") return tokenized; | ||
if (isFunction) { | ||
rootTypeTokens.push(FunctionTypeToken(tokenized.value)); | ||
} else { | ||
for (const t of tokenized.value) { | ||
rootTypeTokens.push(t); | ||
} | ||
} | ||
} else if (currentBuffer.find((t) => t.kind === "ArrowToken")) { | ||
const tokenized = tokenizeType(currentBuffer); | ||
if (tokenized.kind === "err") return tokenized; | ||
default: { | ||
return Err(`Unexpected ${token.kind} while parsing type.`); | ||
rootTypeTokens.push(FunctionTypeToken(tokenized.value)); | ||
} else { | ||
let inner: TypeToken[] = [ ]; | ||
if (currentBuffer.length > 1) { | ||
for (const bufferPart of currentBuffer.slice(1)) { | ||
const tokenized = tokenizeType([ bufferPart ]); | ||
if (tokenized.kind === "err") return tokenized; | ||
inner = inner.concat(tokenized.value); | ||
} | ||
} | ||
rootTypeTokens.push(BaseTypeToken([ currentBuffer[0], ...inner ])); | ||
} | ||
} | ||
if (currentToken.length > 0) { | ||
if (isInFunction) { | ||
return Err("Didn't find matching closing bracket parsing type."); | ||
} | ||
typeTokens.push(BaseTypeToken(currentToken)); | ||
} | ||
return Ok(typeTokens); | ||
return Ok(rootTypeTokens); | ||
} | ||
@@ -844,2 +901,14 @@ | ||
function isNested(token: RootTypeTokens): boolean { | ||
switch (token.kind) { | ||
case "BaseTypeToken": { | ||
if (token.body.length === 1) return false; | ||
return true; | ||
} | ||
case "FunctionTypeToken": { | ||
return true; | ||
} | ||
} | ||
} | ||
export function rootTypeTokensToString(tokens: RootTypeTokens[]): string { | ||
@@ -853,7 +922,11 @@ const output: string[] = [ ]; | ||
if (value.kind === "BaseTypeToken") { | ||
output.push(typeTokenToString(OpenBracketToken())); | ||
if (isNested(value)) { | ||
output.push(typeTokenToString(OpenBracketToken())); | ||
} | ||
value.body.forEach((v) => | ||
output.push(typeTokenToString(v)) | ||
); | ||
output.push(typeTokenToString(CloseBracketToken())); | ||
if (isNested(value)) { | ||
output.push(typeTokenToString(CloseBracketToken())); | ||
} | ||
} else { | ||
@@ -867,4 +940,7 @@ output.push(typeTokenToString(value)); | ||
output.push(typeTokenToString(OpenBracketToken())); | ||
token.body.forEach((value) => { | ||
token.body.forEach((value, i) => { | ||
output.push(typeTokenToString(value)); | ||
if (i < token.body.length - 1) { | ||
output.push(typeTokenToString(ArrowToken())); | ||
} | ||
}); | ||
@@ -871,0 +947,0 @@ output.push(typeTokenToString(CloseBracketToken())); |
@@ -173,3 +173,18 @@ import { isBuiltinType } from "./builtins"; | ||
function generateObjectLiteralWithBase(literal: ObjectLiteral): string { | ||
const base = (literal.base as Value).body; | ||
if (literal.fields.length === 0) return `{ ${base} }`; | ||
let fields = literal.fields.map(generateField).join(",\n "); | ||
if (literal.fields.length === 1) return `{ ${base}, ${fields} }`; | ||
return `{ | ||
${base}, | ||
${fields} | ||
}`; | ||
} | ||
function generateObjectLiteral(literal: ObjectLiteral): string { | ||
if (literal.base !== null) return generateObjectLiteralWithBase(literal); | ||
if (literal.fields.length === 0) return `{ }`; | ||
@@ -176,0 +191,0 @@ |
@@ -155,2 +155,4 @@ import { Maybe } from "@eeue56/ts-core/build/main/lib/maybe"; | ||
export type ObjectLiteralBase = Value | null; | ||
export type Field = { | ||
@@ -172,8 +174,13 @@ kind: "Field"; | ||
kind: "ObjectLiteral"; | ||
base: ObjectLiteralBase; | ||
fields: Field[]; | ||
}; | ||
export function ObjectLiteral(fields: Field[]): ObjectLiteral { | ||
export function ObjectLiteral( | ||
base: ObjectLiteralBase, | ||
fields: Field[] | ||
): ObjectLiteral { | ||
return { | ||
kind: "ObjectLiteral", | ||
base, | ||
fields, | ||
@@ -180,0 +187,0 @@ }; |
Sorry, the diff of this file is too big to display
579664
97
16888
473