From eb0bd03c2fa605331d1531ef55897fcd06baa803 Mon Sep 17 00:00:00 2001 From: xTrayambak Date: Sat, 28 Sep 2024 11:08:41 +0530 Subject: [PATCH] (fmt) run formatter --- bali.nimble | 14 +- src/bali.nim | 1 + src/bali/balde.nim | 51 ++- src/bali/grammar/ast.nim | 30 +- src/bali/grammar/parser.nim | 249 +++++++------- src/bali/grammar/scopes.nim | 1 + src/bali/grammar/statement.nim | 140 +++----- src/bali/grammar/token.nim | 43 +-- src/bali/grammar/tokenizer.nim | 140 +++----- src/bali/internal/sugar.nim | 3 +- src/bali/internal/trim_string.nim | 21 +- src/bali/runtime/abstract/to_number.nim | 25 +- src/bali/runtime/abstract/to_string.nim | 21 +- src/bali/runtime/atom_helpers.nim | 2 +- src/bali/runtime/interpreter.nim | 428 +++++++++++++----------- src/bali/runtime/normalize.nim | 8 +- src/bali/runtime/objects.nim | 10 +- src/bali/stdlib/builtins/base64.nim | 21 +- src/bali/stdlib/builtins/parse_int.nim | 33 +- src/bali/stdlib/builtins/test262.nim | 38 +-- src/bali/stdlib/console.nim | 42 +-- src/bali/stdlib/errors.nim | 20 +- src/bali/stdlib/math.nim | 89 ++--- src/bali/stdlib/uri.nim | 90 ++--- tests/common.nim | 2 +- tests/config.nims | 2 +- tests/parser/t001.nim | 6 +- tests/parser/t002.nim | 6 +- tests/runtime/t001.nim | 12 +- tests/runtime/t003.nim | 6 +- tests/runtime/t004.nim | 4 +- tests/runtime/t005.nim | 12 +- tests/runtime/thing.nim | 8 +- tests/string_trim.nim | 4 +- tests/test262.nim | 37 +- tests/tokenizer/t001.nim | 6 +- 36 files changed, 795 insertions(+), 830 deletions(-) diff --git a/bali.nimble b/bali.nimble index 036059a..028b1f2 100644 --- a/bali.nimble +++ b/bali.nimble @@ -1,11 +1,11 @@ # Package -version = "0.3.0" -author = "xTrayambak" -description = "The Bali JavaScript Engine" -license = "MIT" -srcDir = "src" -backend = "cpp" +version = "0.3.0" +author = "xTrayambak" +description = "The Bali JavaScript Engine" +license = "MIT" +srcDir = "src" +backend = "cpp" # Dependencies @@ -33,4 +33,4 @@ task test262, "Compile the Test262 suite tester against Bali": exec "nim c -d:release --path:src -o:./test262 tests/test262.nim" -requires "https://github.com/ferus-web/sanchar >= 2.0.0" \ No newline at end of file +requires "https://github.com/ferus-web/sanchar >= 2.0.0" diff --git a/src/bali.nim b/src/bali.nim index e69de29..8b13789 100644 --- a/src/bali.nim +++ b/src/bali.nim @@ -0,0 +1 @@ + diff --git a/src/bali/balde.nim b/src/bali/balde.nim index 7818d7d..4d0ff40 100644 --- a/src/bali/balde.nim +++ b/src/bali/balde.nim @@ -11,11 +11,11 @@ import bali/internal/sugar import bali/runtime/prelude import climate, colored_logger, jsony, pretty -var +var enableProfiler = false profile = initTable[string, int64]() -proc enableLogging {.inline.} = +proc enableLogging() {.inline.} = addHandler newColoredLogger() template profileThis(task: string, body: untyped) = @@ -24,7 +24,7 @@ template profileThis(task: string, body: untyped) = start = getMonoTime() body - + if enableProfiler: let ant = getMonoTime() profile[task] = inMilliseconds(ant - start) @@ -42,17 +42,18 @@ proc execFile(ctx: Context, file: string) {.inline.} = profileThis "execFile() sanity checks": if not fileExists(file): die "file not found:", file - + let perms = getFilePermissions(file) if fpGroupRead notin perms and fpUserRead notin perms: die "access denied:", file profileThis "read source file": - let source = try: - readFile(file) - except IOError as exc: - die "failed to open file:", exc.msg - "" + let source = + try: + readFile(file) + except IOError as exc: + die "failed to open file:", exc.msg + "" if ctx.cmdOptions.contains("dump-tokens"): let excludeWs = ctx.cmdOptions.contains("no-whitespace") @@ -60,29 +61,27 @@ proc execFile(ctx: Context, file: string) {.inline.} = while not tok.eof: if excludeWs: let val = tok.nextExceptWhitespace() - if !val: break + if !val: + break print &val else: print tok.next() quit(0) - profileThis "allocate parser": + profileThis "allocate parser": let parser = newParser(source) - + profileThis "parse source code": let ast = parser.parse() if ctx.cmdOptions.contains("dump-ast"): print ast quit(0) - + profileThis "allocate runtime": let runtime = newRuntime( - file, ast, - InterpreterOpts( - test262: ctx.cmdOptions.contains("test262") - ) + file, ast, InterpreterOpts(test262: ctx.cmdOptions.contains("test262")) ) profileThis "execution time": @@ -95,28 +94,24 @@ proc baldeRun(ctx: Context): int = if not ctx.cmdOptions.contains("verbose") or ctx.cmdOptions.contains("v"): setLogFilter(lvlWarn) - enableProfiler = ctx.cmdOptions.contains("enable-profiler") or ctx.cmdOptions.contains("P") + enableProfiler = + ctx.cmdOptions.contains("enable-profiler") or ctx.cmdOptions.contains("P") ctx.arg: execFile(ctx, arg) do: die "`run` requires a file to evaluate." -proc main {.inline.} = +proc main() {.inline.} = enableLogging() - const commands = { - "run": baldeRun - } + const commands = {"run": baldeRun} let value = parseCommands(commands) - + if enableProfiler: - writeFile( - "balde_profiler.txt", - toJson profile - ) - + writeFile("balde_profiler.txt", toJson profile) + quit(value) when isMainModule: diff --git a/src/bali/grammar/ast.nim b/src/bali/grammar/ast.nim index 7247087..fed84aa 100644 --- a/src/bali/grammar/ast.nim +++ b/src/bali/grammar/ast.nim @@ -3,12 +3,11 @@ import bali/internal/sugar import pretty import ./[statement, scopes] -type - AST* = ref object - currentScope*: int - scopes*: seq[Scope] +type AST* = ref object + currentScope*: int + scopes*: seq[Scope] - doNotEvaluate*: bool = false # For Test262 + doNotEvaluate*: bool = false # For Test262 proc `&=`*(ast: AST, scope: Scope) = ast.scopes &= scope @@ -31,23 +30,22 @@ proc append*(ast: AST, name: string, stmt: Statement) = if fn.name == name: fn.stmts &= stmt return - + raise newException(ValueError, "No such scope: " & name) iterator items*(ast: AST): Scope = for scope in ast.scopes: yield scope -func function*(name: string, stmts: seq[Statement], args: seq[string]): Function {.inline.} = - Function( - name: name, - stmts: stmts, - arguments: args - ) +func function*( + name: string, stmts: seq[Statement], args: seq[string] +): Function {.inline.} = + Function(name: name, stmts: stmts, arguments: args) -proc newAST*: AST {.inline.} = +proc newAST*(): AST {.inline.} = AST( - scopes: @[ - Scope() # top-level scope - ] + scopes: + @[ + Scope() # top-level scope + ] ) diff --git a/src/bali/grammar/parser.nim b/src/bali/grammar/parser.nim index 7c958ca..a7ca57f 100644 --- a/src/bali/grammar/parser.nim +++ b/src/bali/grammar/parser.nim @@ -26,9 +26,8 @@ type errors*: seq[ParseError] template error(parser: Parser, kind: ParseErrorKind, msg: string) = - parser.errors &= - ParseError(location: parser.tokenizer.location, message: msg) - + parser.errors &= ParseError(location: parser.tokenizer.location, message: msg) + return proc `$`*(error: ParseError): string = @@ -47,7 +46,11 @@ proc parseArguments*(parser: Parser): Option[PositionedArguments] proc parseFunctionCall*(parser: Parser, name: string): Option[Statement] = let args = parser.parseArguments() - arguments = if *args: &args else: newSeq[CallArg](0) + arguments = + if *args: + &args + else: + newSeq[CallArg](0) if name == "$DONOTEVALUATE": parser.ast.doNotEvaluate = true @@ -56,20 +59,28 @@ proc parseFunctionCall*(parser: Parser, name: string): Option[Statement] = proc parseAtom*(parser: Parser, token: Token): Option[MAtom] -proc parseExpression*(parser: Parser, storeIn: Option[string] = none(string)): Option[Statement] = +proc parseExpression*( + parser: Parser, storeIn: Option[string] = none(string) +): Option[Statement] = info "parser: parsing arithmetic/binary expression" var term = Statement(kind: BinaryOp, binStoreIn: storeIn) template parseRHSExpression(otherRight: Statement) = debug "parser: " & $otherRight.kind & " will fill right term" var copiedTok = deepCopy(parser.tokenizer) - if not parser.tokenizer.eof() and (let andSymbol = parser.tokenizer.nextExceptWhitespace(); *andSymbol): + if not parser.tokenizer.eof() and + (let andSymbol = parser.tokenizer.nextExceptWhitespace(); *andSymbol): case (&andSymbol).kind of TokenKind.And, TokenKind.Or: let expr = parser.parseExpression() if *expr: - term.binLeft = Statement(kind: BinaryOp, binStoreIn: storeIn, binLeft: term.binLeft, binRight: otherRight) + term.binLeft = Statement( + kind: BinaryOp, + binStoreIn: storeIn, + binLeft: term.binLeft, + binRight: otherRight, + ) term.binRight = &expr break else: @@ -116,7 +127,7 @@ proc parseExpression*(parser: Parser, storeIn: Option[string] = none(string)): O term.op = BinaryOperation.NotEqual of TokenKind.Whitespace: debug "parser: whilst parsing arithmetic expr, found whitespace" - if next.isNewline(): + if next.isNewline(): debug "parser: whitespace contains newline, aborting expr parsing" break of TokenKind.LParen: @@ -146,7 +157,8 @@ proc parseExpression*(parser: Parser, storeIn: Option[string] = none(string)): O debug "parser: boolean will fill right term" term.binRight = atomHolder(boolean(false)) else: - debug "parser: met unexpected token " & $next.kind & " during tokenization, marking expression parse as failed" + debug "parser: met unexpected token " & $next.kind & + " during tokenization, marking expression parse as failed" return if term.binLeft != nil and term.binRight != nil: @@ -159,22 +171,21 @@ proc parseConstructor*(parser: Parser): Option[Statement] = if !next: parser.error UnexpectedToken, "expected Identifier, got EOF" - + if (&next).kind != TokenKind.Identifier: parser.error UnexpectedToken, "expected Identifier, got " & $(&next).kind if not parser.tokenizer.eof() and parser.tokenizer.next().kind != TokenKind.LParen: parser.error Other, "expected left parenthesis when creating object constructor" - - return some( - constructObject((&next).ident, - &parser.parseArguments() - )) -proc parseDeclaration*(parser: Parser, initialIdent: string, reassignment: bool = false): Option[Statement] = + return some(constructObject((&next).ident, &parser.parseArguments())) + +proc parseDeclaration*( + parser: Parser, initialIdent: string, reassignment: bool = false +): Option[Statement] = info "parser: parse declaration" var ident = initialIdent - + if not reassignment: while not parser.tokenizer.eof: let tok = &parser.tokenizer.nextExceptWhitespace() @@ -184,12 +195,13 @@ proc parseDeclaration*(parser: Parser, initialIdent: string, reassignment: bool ident = tok.ident of TokenKind.EqualSign: break # weird quirky javascript feature :3 (I hate brendan eich) - of TokenKind.Whitespace: continue + of TokenKind.Whitespace: + continue of TokenKind.Number: parser.error UnexpectedToken, "numeric literal" else: parser.error UnexpectedToken, $tok.kind - + let copiedTok = parser.tokenizer.deepCopy() expr = parser.parseExpression(ident.some()) @@ -208,15 +220,13 @@ proc parseDeclaration*(parser: Parser, initialIdent: string, reassignment: bool while not parser.tokenizer.eof and !vIdent and !atom: let tok = parser.tokenizer.next() - + case tok.kind of TokenKind.String: if tok.malformed: error Other, "string literal is malformed" - atom = some( - str tok.str - ) + atom = some(str tok.str) break of TokenKind.Identifier: if not parser.tokenizer.eof() and parser.tokenizer.next().kind == TokenKind.LParen: @@ -225,25 +235,25 @@ proc parseDeclaration*(parser: Parser, initialIdent: string, reassignment: bool break else: # just an ident copy - vIdent = some( - tok.ident - ) + vIdent = some(tok.ident) break of TokenKind.Number: if *tok.intVal: - atom = some( - uinteger uint32(&tok.intVal) - ) - of TokenKind.Whitespace: discard + atom = some(uinteger uint32(&tok.intVal)) + of TokenKind.Whitespace: + discard of TokenKind.New: toCall = parser.parseConstructor() break - else: unreachable - - assert not (*atom and *vIdent and *toCall), "Attempt to assign a value to nothing (something went wrong)" + else: + unreachable + + assert not (*atom and *vIdent and *toCall), + "Attempt to assign a value to nothing (something went wrong)" + + if *vIdent: + parser.error Other, "assignment from another address is not supported yet" - if *vIdent: parser.error Other, "assignment from another address is not supported yet" - if not reassignment: case initialIdent of "let", "const": @@ -256,7 +266,8 @@ proc parseDeclaration*(parser: Parser, initialIdent: string, reassignment: bool return some(createMutVal(ident, &atom)) elif *toCall: return some(callAndStoreMut(ident, &toCall)) - else: unreachable + else: + unreachable else: if not reassignment: if *atom: @@ -281,20 +292,21 @@ proc parseFunction*(parser: Parser): Option[Function] = of TokenKind.Identifier: name = some(tok.ident) break - else: discard + else: + discard if not *name: parser.error Other, "function statement requires a name" - var + var metLParen = false metRParen = false - arguments: seq[string] + arguments: seq[string] # TODO: parameter parsing while not parser.tokenizer.eof: let tok = parser.tokenizer.next() - + case tok.kind of TokenKind.LParen: info "parser: met left-paren" @@ -303,7 +315,7 @@ proc parseFunction*(parser: Parser): Option[Function] = of TokenKind.RParen: info "parser: met right-paren" metRParen = true - + if not metLParen: parser.error Other, "missing ( before formal parameters" of TokenKind.LCurly: @@ -311,20 +323,21 @@ proc parseFunction*(parser: Parser): Option[Function] = if not metLParen: parser.error Other, "missing ( before start of function scope" - + if not metRParen: parser.error Other, "missing ) before start of function scope" break - of TokenKind.Whitespace: discard + of TokenKind.Whitespace: + discard of TokenKind.Identifier: - info "parser: appending identifier to expected function argument signature: " & tok.ident + info "parser: appending identifier to expected function argument signature: " & + tok.ident if metRParen: parser.error Other, "unexpected identifier after end of function signature" - arguments &= - tok.ident - else: + arguments &= tok.ident + else: warn "parser (unimplemented): whilst parsing parameters: " print tok discard # parameter parser goes here :3 @@ -332,7 +345,7 @@ proc parseFunction*(parser: Parser): Option[Function] = var body: seq[Statement] info "parser: parse function body: " & &name while not parser.tokenizer.eof: - let + let prevPos = parser.tokenizer.pos prevLoc = parser.tokenizer.location c = parser.tokenizer.nextExceptWhitespace() @@ -343,11 +356,12 @@ proc parseFunction*(parser: Parser): Option[Function] = else: parser.tokenizer.pos = prevPos parser.tokenizer.location = prevLoc - + let stmt = parser.parseStatement() if not *stmt: - info "parser: can't find any more statements for function body: " & &name & "; body parsing complete" + info "parser: can't find any more statements for function body: " & &name & + "; body parsing complete" break var statement = &stmt @@ -355,26 +369,23 @@ proc parseFunction*(parser: Parser): Option[Function] = statement.col = parser.tokenizer.location.col body &= statement - + info "parser: parsed function: " & &name some function(&name, body, arguments) proc parseAtom*(parser: Parser, token: Token): Option[MAtom] = info "parser: trying to parse an atom out of " & $token.kind - + case token.kind of TokenKind.Number: if *token.intVal: - return some integer( - &token.intVal - ) + return some integer(&token.intVal) else: return some floating(token.floatVal) of TokenKind.String: - return some str( - token.str - ) - else: unreachable + return some str(token.str) + else: + unreachable proc parseArguments*(parser: Parser): Option[PositionedArguments] = info "parser: parse arguments for function call" @@ -386,7 +397,7 @@ proc parseArguments*(parser: Parser): Option[PositionedArguments] = while not parser.tokenizer.eof(): inc idx let copiedTok = deepCopy(parser.tokenizer) - + if (let expr = parser.parseExpression(); *expr): debug "parser: whilst parsing arguments in function call, found expression" args.pushImmExpr(&expr) @@ -398,7 +409,8 @@ proc parseArguments*(parser: Parser): Option[PositionedArguments] = let token = parser.tokenizer.next() case token.kind - of TokenKind.Whitespace, TokenKind.Comma: discard + of TokenKind.Whitespace, TokenKind.Comma: + discard of TokenKind.Identifier: let prevPos = parser.tokenizer.pos @@ -406,16 +418,11 @@ proc parseArguments*(parser: Parser): Option[PositionedArguments] = if parser.tokenizer.next().kind == TokenKind.LParen: # function! - let + let call = parser.parseFunctionCall(token.ident) resIdent = "@0_" & $idx - parser.ast.appendToCurrentScope( - callAndStoreMut( - resIdent, - &call - ) - ) + parser.ast.appendToCurrentScope(callAndStoreMut(resIdent, &call)) args.pushIdent(resIdent) else: parser.tokenizer.pos = prevPos @@ -436,13 +443,16 @@ proc parseArguments*(parser: Parser): Option[PositionedArguments] = let atom = parser.parseAtom(token) if !atom: - parser.error Other, "expected atom, got malformed data instead." # FIXME: make this less vague! + parser.error Other, "expected atom, got malformed data instead." + # FIXME: make this less vague! args.pushAtom(&atom) of TokenKind.RParen: metEnd = true break - else: print token; unreachable + else: + print token + unreachable if not metEnd: parser.error Other, "missing ) after argument list." @@ -450,7 +460,7 @@ proc parseArguments*(parser: Parser): Option[PositionedArguments] = some args proc parseConditions*(parser: Parser): Option[Condition] = - var + var metLParen = false lastGate: Gate cond: Condition @@ -462,7 +472,8 @@ proc parseConditions*(parser: Parser): Option[Condition] = cond.append(&parser.parseConditions(), lastGate) of TokenKind.And: lastGate = Gate.And - else: unreachable + else: + unreachable some(cond) @@ -477,7 +488,8 @@ proc parseThrow*(parser: Parser): Option[Statement] = let next = parser.tokenizer.next() if next.kind == TokenKind.Whitespace and next.whitespace.contains(strutils.Newlines): - parser.error UnexpectedToken, "no line break is allowed between 'throw' and its expression" + parser.error UnexpectedToken, + "no line break is allowed between 'throw' and its expression" if next.kind == TokenKind.String: throwStr = some(next.str) @@ -486,12 +498,7 @@ proc parseThrow*(parser: Parser): Option[Statement] = if !throwStr and !throwErr: parser.error Other, "throw statement is missing an expression" - some( - throwError( - throwStr, - throwErr - ) - ) + some(throwError(throwStr, throwErr)) proc parseReassignment*(parser: Parser, ident: string): Option[Statement] = info "parser: parsing re-assignment" @@ -503,15 +510,13 @@ proc parseReassignment*(parser: Parser, ident: string): Option[Statement] = while not parser.tokenizer.eof and !vIdent and !atom: let tok = parser.tokenizer.next() - + case tok.kind of TokenKind.String: if tok.malformed: error Other, "string literal is malformed" - atom = some( - str tok.str - ) + atom = some(str tok.str) break of TokenKind.Identifier: if not parser.tokenizer.eof() and parser.tokenizer.next().kind == TokenKind.LParen: @@ -520,35 +525,30 @@ proc parseReassignment*(parser: Parser, ident: string): Option[Statement] = break else: # just an ident copy - vIdent = some( - tok.ident - ) + vIdent = some(tok.ident) break of TokenKind.Number: if *tok.intVal: - atom = some( - uinteger uint32(&tok.intVal) - ) - of TokenKind.Whitespace: discard + atom = some(uinteger uint32(&tok.intVal)) + of TokenKind.Whitespace: + discard of TokenKind.New: let next = parser.tokenizer.nextExceptWhitespace() if !next: parser.error UnexpectedToken, "expected Identifier, got EOF" - + if (&next).kind != TokenKind.Identifier: parser.error UnexpectedToken, "expected Identifier, got " & $(&next).kind if not parser.tokenizer.eof() and parser.tokenizer.next().kind != TokenKind.LParen: parser.error Other, "expected left parenthesis when creating object constructor" - toCall = some( - constructObject((&next).ident, - &parser.parseArguments() - )) + toCall = some(constructObject((&next).ident, &parser.parseArguments())) break - else: unreachable - + else: + unreachable + if *atom: return some(reassignVal(ident, &atom)) elif *toCall: @@ -562,7 +562,7 @@ proc parseStatement*(parser: Parser): Option[Statement] = if !tok: return #parser.error Other, "expected statement, got whitespace/EOF instead." - + let token = &tok case token.kind @@ -578,42 +578,44 @@ proc parseStatement*(parser: Parser): Option[Statement] = of TokenKind.Function: info "parser: parse function declaration" let fnOpt = parser.parseFunction() - + if !fnOpt: parser.error Other, "unexpected end of input" - + var fn = &fnOpt - + var scope = parser.ast.scopes[0] - + while *scope.next: scope = &scope.next - + fn.prev = some(scope) scope.next = some(Scope(fn)) of TokenKind.Identifier: - let + let prevPos = parser.tokenizer.pos prevLoc = parser.tokenizer.location - + if not parser.tokenizer.eof(): let next = parser.tokenizer.nextExceptWhitespace() if !next: - return # FIXME: should we expand this into a `Call("console.log", `ident`)` instead? - + return + # FIXME: should we expand this into a `Call("console.log", `ident`)` instead? + case (&next).kind of TokenKind.LParen: return parser.parseFunctionCall(token.ident) #some call(token.ident, arguments) of TokenKind.EqualSign: return parser.parseReassignment(token.ident) else: - parser.error UnexpectedToken, "expected left parenthesis or equal sign, got " & $(&next).kind - + parser.error UnexpectedToken, + "expected left parenthesis or equal sign, got " & $(&next).kind + parser.tokenizer.pos = prevPos parser.tokenizer.location = prevLoc of TokenKind.Return: - let + let prevPos = parser.tokenizer.pos prevLoc = parser.tokenizer.location @@ -628,8 +630,9 @@ proc parseStatement*(parser: Parser): Option[Statement] = of TokenKind.Whitespace: if next.whitespace.contains(strutils.Newlines): return some returnFunc() - else: unreachable - + else: + unreachable + parser.tokenizer.pos = prevPos parser.tokenizer.location = prevLoc return some returnFunc() @@ -661,7 +664,7 @@ proc parseStatement*(parser: Parser): Option[Statement] = var body: seq[Statement] info "parser: parse if-statement body" while not parser.tokenizer.eof: - let + let prevPos = parser.tokenizer.pos prevLoc = parser.tokenizer.location c = parser.tokenizer.nextExceptWhitespace() @@ -672,7 +675,7 @@ proc parseStatement*(parser: Parser): Option[Statement] = else: parser.tokenizer.pos = prevPos parser.tokenizer.location = prevLoc - + let stmt = parser.parseStatement() if not *stmt: @@ -684,7 +687,7 @@ proc parseStatement*(parser: Parser): Option[Statement] = statement.col = parser.tokenizer.location.col body &= statement - + var lastScope = parser.ast.scopes[parser.ast.currentScope] var exprScope = Scope(stmts: body) exprScope.prev = some(lastScope) @@ -696,16 +699,20 @@ proc parseStatement*(parser: Parser): Option[Statement] = parser.error Other, "expected expression for `new`" return expr - of TokenKind.Comment, TokenKind.String, TokenKind.Number, TokenKind.Null: discard - of TokenKind.Shebang, TokenKind.Semicolon: discard - else: print token; unreachable + of TokenKind.Comment, TokenKind.String, TokenKind.Number, TokenKind.Null: + discard + of TokenKind.Shebang, TokenKind.Semicolon: + discard + else: + print token + unreachable proc parse*(parser: Parser): AST {.inline.} = parser.ast = newAST() while not parser.tokenizer.eof(): let stmt = parser.parseStatement() - + if *stmt: var statement = &stmt statement.line = parser.tokenizer.location.line @@ -715,6 +722,4 @@ proc parse*(parser: Parser): AST {.inline.} = parser.ast proc newParser*(input: string): Parser {.inline.} = - Parser( - tokenizer: newTokenizer(input) - ) + Parser(tokenizer: newTokenizer(input)) diff --git a/src/bali/grammar/scopes.nim b/src/bali/grammar/scopes.nim index e69de29..8b13789 100644 --- a/src/bali/grammar/scopes.nim +++ b/src/bali/grammar/scopes.nim @@ -0,0 +1 @@ + diff --git a/src/bali/grammar/statement.nim b/src/bali/grammar/statement.nim index 4ede179..b400f3a 100644 --- a/src/bali/grammar/statement.nim +++ b/src/bali/grammar/statement.nim @@ -47,7 +47,7 @@ type Function* = ref object of Scope name*: string = "outer" arguments*: seq[string] ## expected arguments! - + BinaryOperation* {.pure.} = enum Add Sub @@ -55,10 +55,8 @@ type Div Pow Invalid - Equal TrueEqual - NotEqual NotTrueEqual @@ -119,44 +117,19 @@ proc hash*(stmt: Statement): Hash {.inline.} = hash = hash !& stmt.kind.int case stmt.kind of CreateMutVal: - hash = hash !& hash( - ( - stmt.mutIdentifier, - stmt.mutAtom - ) - ) + hash = hash !& hash((stmt.mutIdentifier, stmt.mutAtom)) of CreateImmutVal: - hash = hash !& hash( - ( - stmt.imIdentifier, - stmt.imAtom - ) - ) + hash = hash !& hash((stmt.imIdentifier, stmt.imAtom)) of Call: - hash = hash !& hash( - ( - stmt.fn, - stmt.arguments - ) - ) + hash = hash !& hash((stmt.fn, stmt.arguments)) of NewFunction: - hash = hash !& hash( - ( - stmt.fnName - ) - ) + hash = hash !& hash((stmt.fnName)) of BinaryOp: - hash = hash !& hash( - (stmt.op, stmt.binLeft, stmt.binRight, stmt.binStoreIn) - ) + hash = hash !& hash((stmt.op, stmt.binLeft, stmt.binRight, stmt.binStoreIn)) of IfStmt: - hash = hash !& hash( - (stmt.conditionExpr) - ) + hash = hash !& hash((stmt.conditionExpr)) of AccessField: - hash = hash !& hash( - (stmt.identifier, stmt.field) - ) + hash = hash !& hash((stmt.identifier, stmt.field)) of AtomHolder: hash = hash !& hash(stmt.atom) of IdentHolder: @@ -167,56 +140,36 @@ proc hash*(stmt: Statement): Hash {.inline.} = hash proc pushIdent*(args: var PositionedArguments, ident: string) {.inline.} = - args &= - CallArg( - kind: cakIdent, - ident: ident - ) + args &= CallArg(kind: cakIdent, ident: ident) -proc pushFieldAccess*(args: var PositionedArguments, ident: string, field: string) {.inline.} = - args &= - CallArg( - kind: cakFieldAccess, - fIdent: ident, - fField: field - ) +proc pushFieldAccess*( + args: var PositionedArguments, ident: string, field: string +) {.inline.} = + args &= CallArg(kind: cakFieldAccess, fIdent: ident, fField: field) proc pushAtom*(args: var PositionedArguments, atom: MAtom) {.inline.} = - args &= - CallArg( - kind: cakAtom, - atom: atom - ) + args &= CallArg(kind: cakAtom, atom: atom) proc pushImmExpr*(args: var PositionedArguments, expr: Statement) {.inline.} = assert expr.kind == BinaryOp, "Attempt to push non expression" - args &= - CallArg( - kind: cakImmediateExpr, - expr: expr - ) + args &= CallArg(kind: cakImmediateExpr, expr: expr) {.push checks: off, inline.} proc throwError*( - errorStr: Option[string], - errorExc: Option[void] # TODO: implement + errorStr: Option[string], errorExc: Option[void], # TODO: implement ): Statement = if *errorStr and *errorExc: - raise newException(ValueError, "Both `errorStr` and `errorExc` are full containers - something has went horribly wrong.") - - Statement( - kind: ThrowError, - error: (str: errorStr, exc: errorExc) - ) + raise newException( + ValueError, + "Both `errorStr` and `errorExc` are full containers - something has went horribly wrong.", + ) + + Statement(kind: ThrowError, error: (str: errorStr, exc: errorExc)) proc createImmutVal*(name: string, atom: MAtom): Statement = - Statement( - kind: CreateImmutVal, - imIdentifier: name, - imAtom: atom - ) + Statement(kind: CreateImmutVal, imIdentifier: name, imAtom: atom) -proc returnFunc*: Statement = +proc returnFunc*(): Statement = Statement(kind: ReturnFn) proc ifStmt*(condition: Statement, body: Scope): Statement = @@ -228,12 +181,19 @@ proc atomHolder*(atom: MAtom): Statement = proc identHolder*(ident: string): Statement = Statement(kind: IdentHolder, ident: ident) -proc binOp*(op: BinaryOperation, left, right: Statement, storeIdent: string = ""): Statement = +proc binOp*( + op: BinaryOperation, left, right: Statement, storeIdent: string = "" +): Statement = Statement( kind: BinaryOp, - binLeft: left, binRight: right, + binLeft: left, + binRight: right, op: op, - binStoreIn: if storeIdent.len > 0: storeIdent.some() else: none(string) + binStoreIn: + if storeIdent.len > 0: + storeIdent.some() + else: + none(string), ) proc reassignVal*(identifier: string, atom: MAtom): Statement = @@ -246,27 +206,13 @@ proc returnFunc*(ident: string): Statement = Statement(kind: ReturnFn, retIdent: some(ident)) proc callAndStoreImmut*(ident: string, fn: Statement): Statement = - Statement( - kind: CallAndStoreResult, - mutable: false, - storeIdent: ident, - storeFn: fn - ) + Statement(kind: CallAndStoreResult, mutable: false, storeIdent: ident, storeFn: fn) proc callAndStoreMut*(ident: string, fn: Statement): Statement = - Statement( - kind: CallAndStoreResult, - mutable: true, - storeIdent: ident, - storeFn: fn - ) + Statement(kind: CallAndStoreResult, mutable: true, storeIdent: ident, storeFn: fn) proc createMutVal*(name: string, atom: MAtom): Statement = - Statement( - kind: CreateMutVal, - mutIdentifier: name, - mutAtom: atom - ) + Statement(kind: CreateMutVal, mutIdentifier: name, mutAtom: atom) proc identArg*(ident: string): CallArg = CallArg(kind: cakIdent, ident: ident) @@ -278,17 +224,9 @@ proc atomArg*(atom: MAtom): CallArg = CallArg(kind: cakAtom, atom: atom) proc constructObject*(name: string, args: PositionedArguments): Statement = - Statement( - kind: ConstructObject, - objName: name, - args: args - ) + Statement(kind: ConstructObject, objName: name, args: args) proc call*(fn: string, arguments: PositionedArguments): Statement = - Statement( - kind: Call, - fn: fn, - arguments: arguments - ) + Statement(kind: Call, fn: fn, arguments: arguments) {.pop.} diff --git a/src/bali/grammar/token.nim b/src/bali/grammar/token.nim index 6627506..615061a 100644 --- a/src/bali/grammar/token.nim +++ b/src/bali/grammar/token.nim @@ -3,7 +3,6 @@ import std/[options, strutils, tables] type TokenKind* {.pure.} = enum Identifier - Break Case Catch @@ -31,18 +30,15 @@ type Void While With - Class Enum Export Extends Import Super - Null True False - Implements Interface Let @@ -52,9 +48,8 @@ type Public Static Yield - - Get, Set - + Get + Set LCurly RCurly LBracket @@ -109,11 +104,9 @@ type BxorEq LAndEq LOrEq - Number String Regexp - Whitespace Comment Invalid @@ -137,23 +130,23 @@ type multiline*: bool of Shebang: shebang*: string - else: discard + else: + discard func isNewline*(token: Token): bool {.inline.} = token.kind == TokenKind.Whitespace and token.whitespace.contains(strutils.Newlines) -const - Keywords* = { - "const": TokenKind.Const, - "let": TokenKind.Let, - "var": TokenKind.Var, - "if": TokenKind.If, - "else": TokenKind.Else, - "true": TokenKind.True, - "false": TokenKind.False, - "new": TokenKind.New, - "debugger": TokenKind.Debugger, - "throw": TokenKind.Throw, - "function": TokenKind.Function, - "return": TokenKind.Return - }.toTable +const Keywords* = { + "const": TokenKind.Const, + "let": TokenKind.Let, + "var": TokenKind.Var, + "if": TokenKind.If, + "else": TokenKind.Else, + "true": TokenKind.True, + "false": TokenKind.False, + "new": TokenKind.New, + "debugger": TokenKind.Debugger, + "throw": TokenKind.Throw, + "function": TokenKind.Function, + "return": TokenKind.Return, +}.toTable diff --git a/src/bali/grammar/tokenizer.nim b/src/bali/grammar/tokenizer.nim index 460830f..eaabb3d 100644 --- a/src/bali/grammar/tokenizer.nim +++ b/src/bali/grammar/tokenizer.nim @@ -13,7 +13,7 @@ type SourceLocation* = object line*, col*: uint - + Tokenizer* = ref object pos*: uint = 0 location*: SourceLocation @@ -22,10 +22,11 @@ type {.push inline, gcsafe.} func eof*(tokenizer: Tokenizer): bool = - let len = if tokenizer.source.len.uint < 1: - 0'u - else: - tokenizer.source.len.uint - 1 + let len = + if tokenizer.source.len.uint < 1: + 0'u + else: + tokenizer.source.len.uint - 1 tokenizer.pos > len @@ -37,7 +38,7 @@ proc consume*(tokenizer: Tokenizer): char = if c == '\n': inc tokenizer.location.line tokenizer.location.col = 0 - + c func hasAtleast*(tokenizer: Tokenizer, num: uint): bool = @@ -58,14 +59,13 @@ proc advance*(tokenizer: Tokenizer, offset: uint = 1) = tokenizer.location.col += offset func newTokenizer*(source: string): Tokenizer = - Tokenizer( - pos: 0, - source: source - ) + Tokenizer(pos: 0, source: source) proc next*(tokenizer: Tokenizer): Token -proc tokenize*(tokenizer: Tokenizer, opts: TokenizerOpts = default(TokenizerOpts)): seq[Token] = +proc tokenize*( + tokenizer: Tokenizer, opts: TokenizerOpts = default(TokenizerOpts) +): seq[Token] = var tokens: seq[Token] while not tokenizer.eof(): @@ -81,9 +81,8 @@ proc consumeInvalid*(tokenizer: Tokenizer): Token = warn "tokenizer: consume invalid token for character: " & (&tokenizer.charAt()).repr() tokenizer.advance() - Token( - kind: TokenKind.Invalid - ) + Token(kind: TokenKind.Invalid) + {.pop.} proc consumeIdentifier*(tokenizer: Tokenizer): Token = @@ -99,20 +98,15 @@ proc consumeIdentifier*(tokenizer: Tokenizer): Token = tokenizer.advance() else: break - + if not Keywords.contains(ident): debug "tokenizer: consumed identifier \"" & ident & "\"" - Token( - kind: TokenKind.Identifier, - ident: ident - ) + Token(kind: TokenKind.Identifier, ident: ident) else: let keyword = Keywords[ident] debug "tokenizer: consumed keyword: " & $keyword - Token( - kind: keyword - ) + Token(kind: keyword) proc consumeWhitespace*(tokenizer: Tokenizer): Token = debug "tokenizer: consume whitespace" @@ -130,10 +124,7 @@ proc consumeWhitespace*(tokenizer: Tokenizer): Token = debug "tokenizer: consumed " & $ws.len & " whitespace character(s)" - Token( - kind: TokenKind.Whitespace, - whitespace: ws - ) + Token(kind: TokenKind.Whitespace, whitespace: ws) proc consumeEquality*(tokenizer: Tokenizer): Token = tokenizer.advance() @@ -162,7 +153,7 @@ proc consumeString*(tokenizer: Tokenizer): Token = debug "tokenizer: consume string with closing character: " & closesWith tokenizer.advance() - var + var str: string ignoreNextQuote = false @@ -171,7 +162,7 @@ proc consumeString*(tokenizer: Tokenizer): Token = if c == closesWith and not ignoreNextQuote: break - + if c == '\\': ignoreNextQuote = true tokenizer.advance() @@ -188,12 +179,8 @@ proc consumeString*(tokenizer: Tokenizer): Token = else: warn "tokenizer: consumed malformed string: " & str warn "tokenizer: this string does not end with the ending character: " & closesWith - - Token( - kind: TokenKind.String, - malformed: malformed, - str: str - ) + + Token(kind: TokenKind.String, malformed: malformed, str: str) proc consumeComment*(tokenizer: Tokenizer, multiline: bool = false): Token = debug "tokenizer: consuming comment" @@ -202,7 +189,7 @@ proc consumeComment*(tokenizer: Tokenizer, multiline: bool = false): Token = while (not tokenizer.eof()): let c = &tokenizer.charAt() - + if not multiline and c in strutils.Newlines: break @@ -212,14 +199,10 @@ proc consumeComment*(tokenizer: Tokenizer, multiline: bool = false): Token = comment &= c tokenizer.advance() - + debug "tokenizer: consumed comment: " & comment - Token( - kind: TokenKind.Comment, - multiline: multiline, - comment: comment - ) + Token(kind: TokenKind.Comment, multiline: multiline, comment: comment) proc consumeSlash*(tokenizer: Tokenizer): Token = tokenizer.advance() @@ -289,17 +272,16 @@ proc consumeNumeric*(tokenizer: Tokenizer, negative: bool = false): Token = var integralPart: float64 digit: uint32 - + while not tokenizer.eof and unpack(charToDecimalDigit(&tokenizer.charAt()), digit): integralPart = integralPart * 10'f64 + digit.float64 tokenizer.advance(1) - + var isInteger = true fractionalPart: float64 = 0'f64 - - if tokenizer.charAt() == some('.') and - &tokenizer.charAt(1) in {'0' .. '9'}: + + if tokenizer.charAt() == some('.') and &tokenizer.charAt(1) in {'0' .. '9'}: isInteger = false tokenizer.advance(1) @@ -359,25 +341,26 @@ proc consumeNumeric*(tokenizer: Tokenizer, negative: bool = false): Token = proc consumePlus*(tokenizer: Tokenizer): Token = tokenizer.advance() - + let next = tokenizer.charAt() if not *next: return Token(kind: TokenKind.Add) - + case &next of '+': tokenizer.advance() return Token(kind: TokenKind.Increment) of strutils.Whitespace: return Token(kind: TokenKind.Add) - else: discard + else: + discard proc consumeAmpersand*(tokenizer: Tokenizer): Token = tokenizer.advance() let next = tokenizer.charAt() if !next: return tokenizer.consumeInvalid() - + case &next of '&': debug "tokenizer: consumed And operand" @@ -392,7 +375,7 @@ proc consumePipe*(tokenizer: Tokenizer): Token = let next = tokenizer.charAt() if !next: return tokenizer.consumeInvalid() - + case &next of '|': debug "tokenizer: consumed Or operand" @@ -407,11 +390,11 @@ proc consumeHash*(tokenizer: Tokenizer): Token = if tokenizer.charAt() == some('!'): # shebang logic tokenizer.advance() - var shebang: string + var shebang: string while not tokenizer.eof: let c = tokenizer.consume() - + case c of strutils.Newlines: break @@ -420,18 +403,15 @@ proc consumeHash*(tokenizer: Tokenizer): Token = tokenizer.advance() - return Token( - kind: TokenKind.Shebang, - shebang: shebang - ) - + return Token(kind: TokenKind.Shebang, shebang: shebang) + tokenizer.consumeInvalid() proc next*(tokenizer: Tokenizer): Token = let c = tokenizer.charAt() case &c - of {'a'..'z'}, {'A'..'Z'}, '_', '$': + of {'a' .. 'z'}, {'A' .. 'Z'}, '_', '$': tokenizer.consumeIdentifier() of strutils.Whitespace: tokenizer.consumeWhitespace() @@ -451,49 +431,31 @@ proc next*(tokenizer: Tokenizer): Token = tokenizer.consumeNumeric(true) else: tokenizer.advance() - return Token( - kind: TokenKind.Sub - ) + return Token(kind: TokenKind.Sub) of '.': tokenizer.advance() - Token( - kind: TokenKind.Dot - ) + Token(kind: TokenKind.Dot) of '(': tokenizer.advance() - Token( - kind: TokenKind.LParen - ) + Token(kind: TokenKind.LParen) of ')': tokenizer.advance() - Token( - kind: TokenKind.RParen - ) + Token(kind: TokenKind.RParen) of '[': tokenizer.advance() - Token( - kind: TokenKind.LBracket - ) + Token(kind: TokenKind.LBracket) of ']': tokenizer.advance() - Token( - kind: TokenKind.RBracket - ) + Token(kind: TokenKind.RBracket) of '{': tokenizer.advance() - Token( - kind: TokenKind.LCurly - ) + Token(kind: TokenKind.LCurly) of '}': tokenizer.advance() - Token( - kind: TokenKind.RCurly - ) + Token(kind: TokenKind.RCurly) of ',': tokenizer.advance() - Token( - kind: TokenKind.Comma - ) + Token(kind: TokenKind.Comma) of '!': tokenizer.consumeExclaimation() of '+': @@ -504,9 +466,7 @@ proc next*(tokenizer: Tokenizer): Token = tokenizer.consumePipe() of ';': tokenizer.advance() - Token( - kind: TokenKind.Semicolon - ) + Token(kind: TokenKind.Semicolon) of '#': tokenizer.consumeHash() of '*': @@ -520,7 +480,7 @@ proc nextExceptWhitespace*(tokenizer: Tokenizer): Option[Token] = while not tokenizer.eof() and tok.kind == TokenKind.Whitespace: tok = tokenizer.next() - + if tok.kind != TokenKind.Whitespace: some tok else: diff --git a/src/bali/internal/sugar.nim b/src/bali/internal/sugar.nim index 21847dd..e84865d 100644 --- a/src/bali/internal/sugar.nim +++ b/src/bali/internal/sugar.nim @@ -19,7 +19,8 @@ proc unpack*[T](opt: Option[T], x: var T): bool = return true false + {.pop.} -template unreachable* = +template unreachable*() = assert false, "Unreachable" diff --git a/src/bali/internal/trim_string.nim b/src/bali/internal/trim_string.nim index ffd2125..6789b01 100644 --- a/src/bali/internal/trim_string.nim +++ b/src/bali/internal/trim_string.nim @@ -9,14 +9,13 @@ import bali/runtime/abstract/[coercible, to_string] import pretty -type - TrimMode* {.pure.} = enum - Left - Right - Both +type TrimMode* {.pure.} = enum + Left + Right + Both proc internalTrim*(str: string, things: set[char], mode: TrimMode): string {.inline.} = - var + var substringStart = 0 substringLength = str.len @@ -27,7 +26,7 @@ proc internalTrim*(str: string, things: set[char], mode: TrimMode): string {.inl if not things.contains(c): break - + substringStart += 1 substringLength -= 1 @@ -44,14 +43,10 @@ proc internalTrim*(str: string, things: set[char], mode: TrimMode): string {.inl return substringLength -= seenWhitespaceLength - + str[substringStart ..< str.len] -proc trimString*( - vm: PulsarInterpreter, - input: MAtom, - where: TrimMode -): string = +proc trimString*(vm: PulsarInterpreter, input: MAtom, where: TrimMode): string = # 1. Let str be ? RequireObjectCoercible(string). let inputString = RequireObjectCoercible(vm, input) diff --git a/src/bali/runtime/abstract/to_number.nim b/src/bali/runtime/abstract/to_number.nim index a9fc7b2..86e1ed3 100644 --- a/src/bali/runtime/abstract/to_number.nim +++ b/src/bali/runtime/abstract/to_number.nim @@ -21,7 +21,7 @@ proc StringToNumber*(vm: PulsarInterpreter, value: MAtom): float = let parsed = parseNumberText(text) if !parsed: return NaN - + return &parsed proc ToNumber*(vm: PulsarInterpreter, value: MAtom): float = @@ -29,18 +29,25 @@ proc ToNumber*(vm: PulsarInterpreter, value: MAtom): float = ## The abstract operation ToNumber takes argument argument (an ECMAScript language value) and returns either ## a normal completion containing a Number or a throw completion. It converts argument to a value of type Number. ## It performs the following steps when called - + case value.kind - of Integer: return float(&value.getInt()) # 1. If argument is a Number, return argument. - of UnsignedInt: return float(&value.getUint()) + of Integer: + return float(&value.getInt()) # 1. If argument is a Number, return argument. + of UnsignedInt: + return float(&value.getUint()) of Object: - if value.isUndefined(): return NaN # 3. If argument is undefined, return NaN. + if value.isUndefined(): + return NaN # 3. If argument is undefined, return NaN. else: vm.typeError("ToPrimitive() is not implemented yet!") - of Null: return 0f # 4. If argument is either null or false, return +0𝔽. + of Null: + return 0f # 4. If argument is either null or false, return +0𝔽. of Boolean: - if not &value.getBool(): return 0f # 4. If argument is either null or false, return +0𝔽. - else: return 1f # 5. If argument is true, return 1𝔽. + if not &value.getBool(): + return 0f # 4. If argument is either null or false, return +0𝔽. + else: + return 1f # 5. If argument is true, return 1𝔽. of String: return vm.StringToNumber(value) - else: unreachable + else: + unreachable diff --git a/src/bali/runtime/abstract/to_string.nim b/src/bali/runtime/abstract/to_string.nim index 80414ee..7045752 100644 --- a/src/bali/runtime/abstract/to_string.nim +++ b/src/bali/runtime/abstract/to_string.nim @@ -26,15 +26,24 @@ proc ToString*(vm: PulsarInterpreter, value: MAtom): string {.inline.} = return "null" # 4. If argument is null, return "null". of Boolean: debug "runtime: toString(): atom is a boolean." - return $(&value.getBool()) # 5. If argument is true, return "true" - # 6. If argument is false, return "false". + return + $(&value.getBool()) + # 5. If argument is true, return "true" + # 6. If argument is false, return "false". of Integer: debug "runtime: toString(): atom is a number (int)." - return $(&value.getInt()) # 7. If argument is a Number, return Number::toString(argument, 10). + return + $(&value.getInt()) + # 7. If argument is a Number, return Number::toString(argument, 10). of Float: debug "runtime: toString(): atom is a number (float)." - return $(&value.getFloat()) # 7. If argument is a Number, return Number::toString(argument, 10). + return + $(&value.getFloat()) + # 7. If argument is a Number, return Number::toString(argument, 10). of UnsignedInt: debug "runtime: toString(): atom is a number (uint)." - return $(&value.getUint()) # 7. If argument is a Number, return Number::toString(argument, 10). - of Sequence: return "undefined" # FIXME: not implemented yet! + return + $(&value.getUint()) + # 7. If argument is a Number, return Number::toString(argument, 10). + of Sequence: + return "undefined" # FIXME: not implemented yet! diff --git a/src/bali/runtime/atom_helpers.nim b/src/bali/runtime/atom_helpers.nim index 6736539..5dfa315 100644 --- a/src/bali/runtime/atom_helpers.nim +++ b/src/bali/runtime/atom_helpers.nim @@ -12,5 +12,5 @@ func isObject*(atom: MAtom): bool {.inline.} = func isNull*(atom: MAtom): bool {.inline.} = atom.kind == Null -func undefined*: MAtom {.inline.} = +func undefined*(): MAtom {.inline.} = obj() diff --git a/src/bali/runtime/interpreter.nim b/src/bali/runtime/interpreter.nim index ef16fff..140d362 100644 --- a/src/bali/runtime/interpreter.nim +++ b/src/bali/runtime/interpreter.nim @@ -30,7 +30,8 @@ type ownerFunc*: Hash of vkInternal: ownerStmt*: Hash - else: discard + else: + discard SemanticErrorKind* = enum UnknownIdentifier @@ -44,7 +45,7 @@ type of ImmutableReassignment: imIdent*: string imNewValue*: MAtom - + InterpreterOpts* = object test262*: bool = false @@ -63,12 +64,16 @@ proc unknownIdentifier*(identifier: string): SemanticError {.inline.} = SemanticError(kind: UnknownIdentifier, unknown: identifier) proc immutableReassignmentAttempt*(stmt: Statement): SemanticError {.inline.} = - SemanticError(kind: ImmutableReassignment, imIdent: stmt.reIdentifier, imNewValue: stmt.reAtom, line: stmt.line, col: stmt.col) + SemanticError( + kind: ImmutableReassignment, + imIdent: stmt.reIdentifier, + imNewValue: stmt.reAtom, + line: stmt.line, + col: stmt.col, + ) proc defaultParams*(fn: Function): IndexParams {.inline.} = - IndexParams( - fn: some fn - ) + IndexParams(fn: some fn) proc internalIndex*(stmt: Statement): IndexParams {.inline.} = IndexParams(priorities: @[vkInternal], stmt: some stmt) @@ -76,23 +81,16 @@ proc internalIndex*(stmt: Statement): IndexParams {.inline.} = proc markInternal*(runtime: Runtime, stmt: Statement, ident: string) = runtime.values &= Value( - kind: vkInternal, - index: runtime.addrIdx, - identifier: ident, - ownerStmt: hash(stmt) + kind: vkInternal, index: runtime.addrIdx, identifier: ident, ownerStmt: hash(stmt) ) - - info "Ident \"" & ident & "\" is being internally marked at index " & $runtime.addrIdx & " with statement hash: " & $hash(stmt) + + info "Ident \"" & ident & "\" is being internally marked at index " & $runtime.addrIdx & + " with statement hash: " & $hash(stmt) inc runtime.addrIdx proc markGlobal*(runtime: Runtime, ident: string) = - runtime.values &= - Value( - kind: vkGlobal, - index: runtime.addrIdx, - identifier: ident - ) + runtime.values &= Value(kind: vkGlobal, index: runtime.addrIdx, identifier: ident) info "Ident \"" & ident & "\" is being globally marked at index " & $runtime.addrIdx @@ -100,12 +98,7 @@ proc markGlobal*(runtime: Runtime, ident: string) = proc markLocal*(runtime: Runtime, fn: Function, ident: string) = runtime.values &= - Value( - kind: vkLocal, - index: runtime.addrIdx, - identifier: ident, - ownerFunc: hash(fn) - ) + Value(kind: vkLocal, index: runtime.addrIdx, identifier: ident, ownerFunc: hash(fn)) info "Ident \"" & ident & "\" is being locally marked at index " & $runtime.addrIdx @@ -114,31 +107,33 @@ proc markLocal*(runtime: Runtime, fn: Function, ident: string) = proc index*(runtime: Runtime, ident: string, params: IndexParams): uint = for value in runtime.values: for prio in params.priorities: - if value.kind != prio: continue - - let cond = case value.kind - of vkGlobal: - value.identifier == ident - of vkLocal: - assert *params.fn - value.identifier == ident and value.ownerFunc == hash(¶ms.fn) - of vkInternal: - assert *params.stmt - value.identifier == ident and value.ownerStmt == hash(¶ms.stmt) - + if value.kind != prio: + continue + + let cond = + case value.kind + of vkGlobal: + value.identifier == ident + of vkLocal: + assert *params.fn + value.identifier == ident and value.ownerFunc == hash(¶ms.fn) + of vkInternal: + assert *params.stmt + value.identifier == ident and value.ownerStmt == hash(¶ms.stmt) + if cond: return value.index - + raise newException(ValueError, "No such ident: " & ident) proc generateIR*( - runtime: Runtime, - fn: Function, - stmt: Statement, - internal: bool = false, - ownerStmt: Option[Statement] = none(Statement), - exprStoreIn: Option[string] = none(string), - parentStmt: Option[Statement] = none(Statement) + runtime: Runtime, + fn: Function, + stmt: Statement, + internal: bool = false, + ownerStmt: Option[Statement] = none(Statement), + exprStoreIn: Option[string] = none(string), + parentStmt: Option[Statement] = none(Statement), ) proc expand*(runtime: Runtime, fn: Function, stmt: Statement, internal: bool = false) = @@ -147,24 +142,29 @@ proc expand*(runtime: Runtime, fn: Function, stmt: Statement, internal: bool = f debug "ir: expand Call statement" for i, arg in stmt.arguments: if arg.kind == cakAtom: - debug "ir: load immutable value to expand Call's immediate arguments: " & arg.atom.crush("") - runtime.generateIR(fn, createImmutVal( - $i, - arg.atom - ), ownerStmt = some(stmt), internal = true) # XXX: should this be mutable? + debug "ir: load immutable value to expand Call's immediate arguments: " & + arg.atom.crush("") + runtime.generateIR( + fn, createImmutVal($i, arg.atom), ownerStmt = some(stmt), internal = true + ) # XXX: should this be mutable? elif arg.kind == cakImmediateExpr: debug "ir: add code to solve expression to expand Call's immediate arguments" runtime.markInternal(stmt, $i) - runtime.generateIR(fn, arg.expr, internal = true, exprStoreIn = some($i), parentStmt = some(stmt)) + runtime.generateIR( + fn, arg.expr, internal = true, exprStoreIn = some($i), parentStmt = some(stmt) + ) of ConstructObject: debug "ir: expand ConstructObject statement" for i, arg in stmt.args: if arg.kind == cakAtom: - debug "ir: load immutable value to ConstructObject's immediate arguments: " & arg.atom.crush("") - runtime.generateIR(fn, createImmutVal( - $hash(stmt) & '_' & $i, - arg.atom - ), ownerStmt = some(stmt), internal = true) # XXX: should this be mutable? + debug "ir: load immutable value to ConstructObject's immediate arguments: " & + arg.atom.crush("") + runtime.generateIR( + fn, + createImmutVal($hash(stmt) & '_' & $i, arg.atom), + ownerStmt = some(stmt), + internal = true, + ) # XXX: should this be mutable? of CallAndStoreResult: debug "ir: expand CallAndStoreResult statement by expanding child Call statement" runtime.expand(fn, stmt.storeFn, internal) @@ -172,12 +172,18 @@ proc expand*(runtime: Runtime, fn: Function, stmt: Statement, internal: bool = f debug "ir: expand ThrowError" if *stmt.error.str: - runtime.generateIR(fn, createImmutVal("error_msg", str(&stmt.error.str)), ownerStmt = some(stmt), internal = true) + runtime.generateIR( + fn, + createImmutVal("error_msg", str(&stmt.error.str)), + ownerStmt = some(stmt), + internal = true, + ) of BinaryOp: debug "ir: expand BinaryOp" if *stmt.binStoreIn: - debug "ir: BinaryOp evaluation will be stored in: " & &stmt.binStoreIn & " (" & $runtime.addrIdx & ')' + debug "ir: BinaryOp evaluation will be stored in: " & &stmt.binStoreIn & " (" & + $runtime.addrIdx & ')' runtime.ir.loadInt(runtime.addrIdx, 0) if not internal: @@ -190,27 +196,39 @@ proc expand*(runtime: Runtime, fn: Function, stmt: Statement, internal: bool = f if stmt.binLeft.kind == AtomHolder: debug "ir: BinaryOp left term is an atom" - runtime.generateIR(fn, createImmutVal("left_term", stmt.binLeft.atom), ownerStmt = some(stmt), internal = true) + runtime.generateIR( + fn, + createImmutVal("left_term", stmt.binLeft.atom), + ownerStmt = some(stmt), + internal = true, + ) #else: # debug "ir: BinaryOp left term is an ident, reserving new index for result" # runtime.generateIR(fn, createImmutVal("store_in", null()), ownerStmt = some(stmt), internal = true) if stmt.binRight.kind == AtomHolder: debug "ir: BinaryOp right term is an atom" - runtime.generateIR(fn, createImmutVal("right_term", stmt.binRight.atom), ownerStmt = some(stmt), internal = true) + runtime.generateIR( + fn, + createImmutVal("right_term", stmt.binRight.atom), + ownerStmt = some(stmt), + internal = true, + ) elif stmt.binRight.kind == IdentHolder: debug "ir: BinaryOp right term is an ident" - else: discard + else: + discard proc verifyNotOccupied*(runtime: Runtime, ident: string, fn: Function): bool = var prev = fn.prev while *prev: - let parked = try: - discard runtime.index(ident, defaultParams(fn)) - true - except ValueError as exc: - false + let parked = + try: + discard runtime.index(ident, defaultParams(fn)) + true + except ValueError as exc: + false if parked: return true @@ -224,9 +242,13 @@ proc semanticError*(runtime: Runtime, error: SemanticError) = runtime.semanticErrors &= error -proc resolveFieldAccess*(runtime: Runtime, fn: Function, stmt: Statement, address: int, field: string): uint = +proc resolveFieldAccess*( + runtime: Runtime, fn: Function, stmt: Statement, address: int, field: string +): uint = let internalName = $(hash(stmt) !& hash(ident) !& hash(field)) - runtime.generateIR(fn, createImmutVal(internalName, null()), internal = true, ownerStmt = some(stmt)) + runtime.generateIR( + fn, createImmutVal(internalName, null()), internal = true, ownerStmt = some(stmt) + ) let accessResult = runtime.addrIdx - 1 # start preparing for call to internal field resolver @@ -238,9 +260,9 @@ proc resolveFieldAccess*(runtime: Runtime, fn: Function, stmt: Statement, addres runtime.ir.loadStr(runtime.addrIdx, field) inc runtime.addrIdx - runtime.ir.passArgument(runtime.addrIdx - 3) # pass `accessResult` - runtime.ir.passArgument(runtime.addrIdx - 2) # pass `address` - runtime.ir.passArgument(runtime.addrIdx - 1) # pass `field` + runtime.ir.passArgument(runtime.addrIdx - 3) # pass `accessResult` + runtime.ir.passArgument(runtime.addrIdx - 2) # pass `address` + runtime.ir.passArgument(runtime.addrIdx - 1) # pass `field` runtime.ir.call("BALI_RESOLVEFIELD") runtime.ir.resetArgs() @@ -249,34 +271,41 @@ proc resolveFieldAccess*(runtime: Runtime, fn: Function, stmt: Statement, addres proc generateIRForScope*(runtime: Runtime, scope: Scope) -proc generateIR*(runtime: Runtime, fn: Function, stmt: Statement, internal: bool = false, ownerStmt: Option[Statement] = none(Statement), exprStoreIn: Option[string] = none(string), parentStmt: Option[Statement] = none(Statement)) = +proc generateIR*( + runtime: Runtime, + fn: Function, + stmt: Statement, + internal: bool = false, + ownerStmt: Option[Statement] = none(Statement), + exprStoreIn: Option[string] = none(string), + parentStmt: Option[Statement] = none(Statement), +) = case stmt.kind of CreateImmutVal: - info "emitter: generate IR for creating immutable value with identifier: " & stmt.imIdentifier + info "emitter: generate IR for creating immutable value with identifier: " & + stmt.imIdentifier case stmt.imAtom.kind of Integer: info "interpreter: generate IR for loading immutable integer" - runtime.ir.loadInt( - runtime.addrIdx, - stmt.imAtom - ) + runtime.ir.loadInt(runtime.addrIdx, stmt.imAtom) of UnsignedInt: info "interpreter: generate IR for loading immutable unsigned integer" runtime.ir.loadUint( runtime.addrIdx, - &stmt.imAtom.getUint() # FIXME: make all mirage integer ops work on unsigned integers whenever possible too. + &stmt.imAtom.getUint(), + # FIXME: make all mirage integer ops work on unsigned integers whenever possible too. ) of String: info "interpreter: generate IR for loading immutable string" - discard runtime.ir.loadStr( - runtime.addrIdx, - stmt.imAtom - ) # FIXME: mirage: loadStr doesn't have the discardable pragma + discard runtime.ir.loadStr(runtime.addrIdx, stmt.imAtom) + # FIXME: mirage: loadStr doesn't have the discardable pragma of Float: info "interpreter: generate IR for loading immutable float" discard runtime.ir.addOp( - IROperation(opcode: LoadFloat, arguments: @[uinteger runtime.addrIdx, stmt.imAtom]) + IROperation( + opcode: LoadFloat, arguments: @[uinteger runtime.addrIdx, stmt.imAtom] + ) ) # FIXME: mirage: loadFloat isn't implemented of Boolean: info "emitter: generate IR for loading immutable boolean" @@ -284,8 +313,10 @@ proc generateIR*(runtime: Runtime, fn: Function, stmt: Statement, internal: bool of Null: info "emitter: generate IR for loading immutable null" runtime.ir.loadNull(runtime.addrIdx) - else: print stmt.imAtom; unreachable - + else: + print stmt.imAtom + unreachable + if not internal: if fn.name.len < 1: runtime.ir.markGlobal(runtime.addrIdx) @@ -298,64 +329,59 @@ proc generateIR*(runtime: Runtime, fn: Function, stmt: Statement, internal: bool case stmt.mutAtom.kind of Integer: info "emitter: generate IR for loading mutable integer" - runtime.ir.loadInt( - runtime.addrIdx, - stmt.mutAtom - ) + runtime.ir.loadInt(runtime.addrIdx, stmt.mutAtom) of UnsignedInt: info "emitter: generate IR for loading mutable unsigned integer" - runtime.ir.loadUint( - runtime.addrIdx, - &stmt.mutAtom.getUint() - ) + runtime.ir.loadUint(runtime.addrIdx, &stmt.mutAtom.getUint()) of String: info "emitter: generate IR for loading mutable string" - discard runtime.ir.loadStr( - runtime.addrIdx, - stmt.mutAtom - ) + discard runtime.ir.loadStr(runtime.addrIdx, stmt.mutAtom) of Float: info "emitter: generate IR for loading mutable float" discard runtime.ir.addOp( - IROperation(opcode: LoadFloat, arguments: @[uinteger runtime.addrIdx, stmt.mutAtom]) + IROperation( + opcode: LoadFloat, arguments: @[uinteger runtime.addrIdx, stmt.mutAtom] + ) ) # FIXME: mirage: loadFloat isn't implemented - else: unreachable - + else: + unreachable + if fn.name.len < 1: runtime.ir.markGlobal(runtime.addrIdx) runtime.markLocal(fn, stmt.mutIdentifier) of Call: if runtime.vm.hasBuiltin(stmt.fn): info "interpreter: generate IR for calling builtin: " & stmt.fn - let args = - (proc(): seq[MAtom] = + let args = ( + proc(): seq[MAtom] = var x: seq[MAtom] for arg in stmt.arguments: x &= uinteger runtime.index(arg.ident, defaultParams(fn)) x - )() + )() - runtime.ir.call( - stmt.fn, args - ) + runtime.ir.call(stmt.fn, args) else: let nam = stmt.fn.normalizeIRName() info "interpreter: generate IR for calling function (normalized): " & nam runtime.expand(fn, stmt, internal) - + for i, arg in stmt.arguments: case arg.kind of cakIdent: - info "interpreter: passing ident parameter to function with ident: " & arg.ident - + info "interpreter: passing ident parameter to function with ident: " & + arg.ident + runtime.ir.passArgument(runtime.index(arg.ident, defaultParams(fn))) of cakAtom: # already loaded via the statement expander let ident = $i info "interpreter: passing atom parameter to function with ident: " & ident runtime.ir.passArgument(runtime.index(ident, internalIndex(stmt))) of cakFieldAccess: - let index = runtime.resolveFieldAccess(fn, stmt, int runtime.index(arg.fIdent, defaultParams(fn)), arg.fField) + let index = runtime.resolveFieldAccess( + fn, stmt, int runtime.index(arg.fIdent, defaultParams(fn)), arg.fField + ) runtime.ir.markGlobal(index) runtime.ir.passArgument(index) of cakImmediateExpr: @@ -366,8 +392,9 @@ proc generateIR*(runtime: Runtime, fn: Function, stmt: Statement, internal: bool runtime.ir.call(nam) runtime.ir.resetArgs() of ReturnFn: - assert not (*stmt.retVal and *stmt.retIdent), "ReturnFn statement cannot have both return atom and return ident at once!" - + assert not (*stmt.retVal and *stmt.retIdent), + "ReturnFn statement cannot have both return atom and return ident at once!" + if *stmt.retVal: let name = $hash(fn) & "_retval" runtime.generateIR(fn, createImmutVal(name, &stmt.retVal)) @@ -383,7 +410,8 @@ proc generateIR*(runtime: Runtime, fn: Function, stmt: Statement, internal: bool runtime.generateIR(fn, stmt.storeFn) let index = runtime.index(stmt.storeIdent, defaultParams(fn)) - debug "emitter: call-and-store result will be stored in ident \"" & stmt.storeIdent & "\" or index " & $index + debug "emitter: call-and-store result will be stored in ident \"" & stmt.storeIdent & + "\" or index " & $index runtime.ir.readRegister(index, Register.ReturnValue) of ConstructObject: runtime.expand(fn, stmt, internal) @@ -398,10 +426,13 @@ proc generateIR*(runtime: Runtime, fn: Function, stmt: Statement, internal: bool info "interpreter: passing atom parameter to function with ident: " & ident runtime.ir.passArgument(runtime.index(ident, internalIndex(stmt))) of cakFieldAccess: - let index = runtime.resolveFieldAccess(fn, stmt, int runtime.index(arg.fIdent, defaultParams(fn)), arg.fField) + let index = runtime.resolveFieldAccess( + fn, stmt, int runtime.index(arg.fIdent, defaultParams(fn)), arg.fField + ) runtime.ir.markGlobal(index) runtime.ir.passArgument(index) - of cakImmediateExpr: discard + of cakImmediateExpr: + discard runtime.ir.call("BALI_CONSTRUCTOR_" & stmt.objName.toUpperAscii()) of ReassignVal: @@ -410,29 +441,22 @@ proc generateIR*(runtime: Runtime, fn: Function, stmt: Statement, internal: bool runtime.semanticError(immutableReassignmentAttempt(stmt)) return - info "emitter: reassign value at index " & $index & " with ident \"" & stmt.reIdentifier & "\" to " & stmt.reAtom.crush("") - + info "emitter: reassign value at index " & $index & " with ident \"" & + stmt.reIdentifier & "\" to " & stmt.reAtom.crush("") + case stmt.reAtom.kind of Integer: - runtime.ir.loadInt( - index, - stmt.reAtom - ) + runtime.ir.loadInt(index, stmt.reAtom) of UnsignedInt: - runtime.ir.loadUint( - index, - &stmt.reAtom.getUint() - ) + runtime.ir.loadUint(index, &stmt.reAtom.getUint()) of String: - discard runtime.ir.loadStr( - index, - stmt.reAtom - ) + discard runtime.ir.loadStr(index, stmt.reAtom) of Float: discard runtime.ir.addOp( IROperation(opcode: LoadFloat, arguments: @[uinteger index, stmt.reAtom]) ) # FIXME: mirage: loadFloat isn't implemented - else: unreachable + else: + unreachable runtime.ir.markGlobal(index) of ThrowError: @@ -450,83 +474,107 @@ proc generateIR*(runtime: Runtime, fn: Function, stmt: Statement, internal: bool info "emitter: emitting IR for binary operation" runtime.expand(fn, stmt, internal) - let + let leftTerm = stmt.binLeft rightTerm = stmt.binRight # TODO: recursive IR generation let - leftIdx = if leftTerm.kind == AtomHolder: - runtime.index("left_term", internalIndex(stmt)) - elif leftTerm.kind == IdentHolder: - runtime.index(leftTerm.ident, defaultParams(fn)) - else: 0 - - rightIdx = if rightTerm.kind == AtomHolder: - runtime.index("right_term", internalIndex(stmt)) - elif rightTerm.kind == IdentHolder: - runtime.index(rightTerm.ident, defaultParams(fn)) - else: 0 - + leftIdx = + if leftTerm.kind == AtomHolder: + runtime.index("left_term", internalIndex(stmt)) + elif leftTerm.kind == IdentHolder: + runtime.index(leftTerm.ident, defaultParams(fn)) + else: + 0 + + rightIdx = + if rightTerm.kind == AtomHolder: + runtime.index("right_term", internalIndex(stmt)) + elif rightTerm.kind == IdentHolder: + runtime.index(rightTerm.ident, defaultParams(fn)) + else: + 0 + case stmt.op - of BinaryOperation.Add: runtime.ir.addInt(leftIdx, rightIdx) - of BinaryOperation.Sub: runtime.ir.subInt(leftIdx, rightIdx) + of BinaryOperation.Add: + runtime.ir.addInt(leftIdx, rightIdx) + of BinaryOperation.Sub: + runtime.ir.subInt(leftIdx, rightIdx) of BinaryOperation.Equal: runtime.ir.equate(leftIdx, rightIdx) # FIXME: really weird bug in mirage's IR generator. wtf? - let + let equalJmp = runtime.ir.addOp(IROperation(opcode: Jump)) - 1 # left == right branch - unequalJmp = runtime.ir.addOp(IROperation(opcode: Jump)) - 1 # left != right branch - + unequalJmp = runtime.ir.addOp(IROperation(opcode: Jump)) - 1 + # left != right branch + # left == right branch - let equalBranch = if leftTerm.kind == AtomHolder: - runtime.ir.loadBool(leftIdx, true) - else: - runtime.ir.loadBool(runtime.index(&stmt.binStoreIn, defaultParams(fn)), true) + let equalBranch = + if leftTerm.kind == AtomHolder: + runtime.ir.loadBool(leftIdx, true) + else: + runtime.ir.loadBool(runtime.index(&stmt.binStoreIn, defaultParams(fn)), true) runtime.ir.overrideArgs(equalJmp, @[uinteger(equalBranch)]) runtime.ir.jump(equalBranch + 3) # left != right branch - let unequalBranch = if leftTerm.kind == AtomHolder: - runtime.ir.loadBool(leftIdx, false) - else: - runtime.ir.loadBool(runtime.index(&stmt.binStoreIn, defaultParams(fn)), false) + let unequalBranch = + if leftTerm.kind == AtomHolder: + runtime.ir.loadBool(leftIdx, false) + else: + runtime.ir.loadBool(runtime.index(&stmt.binStoreIn, defaultParams(fn)), false) runtime.ir.overrideArgs(unequalJmp, @[uinteger(unequalBranch)]) of BinaryOperation.NotEqual: runtime.ir.equate(leftIdx, rightIdx) # FIXME: really weird bug in mirage's IR generator. wtf? - let equalJmp = runtime.ir.addOp(IROperation(opcode: Jump)) - 1 # left == right branch - let unequalJmp = runtime.ir.addOp(IROperation(opcode: Jump)) - 1 # left != right branch - + let equalJmp = runtime.ir.addOp(IROperation(opcode: Jump)) - 1 + # left == right branch + let unequalJmp = runtime.ir.addOp(IROperation(opcode: Jump)) - 1 + # left != right branch + # left != right branch: true - let unequalBranch = if leftTerm.kind == AtomHolder: - runtime.ir.loadBool(leftIdx, true) - else: - runtime.ir.loadBool(runtime.index(&stmt.binStoreIn, defaultParams(fn)), true) + let unequalBranch = + if leftTerm.kind == AtomHolder: + runtime.ir.loadBool(leftIdx, true) + else: + runtime.ir.loadBool(runtime.index(&stmt.binStoreIn, defaultParams(fn)), true) runtime.ir.overrideArgs(unequalJmp, @[uinteger(unequalBranch)]) runtime.ir.jump(unequalBranch + 3) # left == right branch: false - let equalBranch = if leftTerm.kind == AtomHolder: - runtime.ir.loadBool(leftIdx, false) - else: - runtime.ir.loadBool(runtime.index(&stmt.binStoreIn, defaultParams(fn)), false) + let equalBranch = + if leftTerm.kind == AtomHolder: + runtime.ir.loadBool(leftIdx, false) + else: + runtime.ir.loadBool(runtime.index(&stmt.binStoreIn, defaultParams(fn)), false) runtime.ir.overrideArgs(equalJmp, @[uinteger(equalBranch)]) else: - warn "emitter: unimplemented binary operation: " & $stmt.op + warn "emitter: unimplemented binary operation: " & $stmt.op if *stmt.binStoreIn: - runtime.ir.moveAtom(leftIdx, runtime.index(&stmt.binStoreIn, if not internal: defaultParams(fn) else: internalIndex(stmt))) + runtime.ir.moveAtom( + leftIdx, + runtime.index( + &stmt.binStoreIn, + if not internal: + defaultParams(fn) + else: + internalIndex(stmt), + ), + ) elif *exprStoreIn: assert *parentStmt - runtime.ir.moveAtom(leftIdx, runtime.index(&exprStoreIn, internalIndex(&parentStmt))) + runtime.ir.moveAtom( + leftIdx, runtime.index(&exprStoreIn, internalIndex(&parentStmt)) + ) of IfStmt: info "emitter: emitting IR for if statement" let trueJump = runtime.ir.addOp(IROperation(opcode: Jump)) - 1 falseJump = runtime.ir.addOp(IROperation(opcode: Jump)) - 1 - + runtime.generateIRForScope(stmt.branchTrue) else: warn "emitter: unimplemented IR generation directive: " & $stmt.kind @@ -536,22 +584,21 @@ proc loadArgumentsOntoStack*(runtime: Runtime, fn: Function) = for i, arg in fn.arguments: runtime.markLocal(fn, arg) - runtime.ir.readRegister(runtime.index(arg, defaultParams(fn)), Register.CallArgument) + runtime.ir.readRegister( + runtime.index(arg, defaultParams(fn)), Register.CallArgument + ) runtime.ir.resetArgs() # reset the call param register proc generateIRForScope*(runtime: Runtime, scope: Scope) = - let + let fn = cast[Function](scope) - name = if fn.name.len > 0: - fn.name - else: - "outer" - + name = if fn.name.len > 0: fn.name else: "outer" + debug "generateIRForScope(): function name: " & name if not runtime.clauses.contains(name): runtime.clauses.add(name) runtime.ir.newModule(name.normalizeIRName()) - + if name != "outer": runtime.loadArgumentsOntoStack(fn) @@ -565,14 +612,16 @@ proc generateIRForScope*(runtime: Runtime, scope: Scope) = proc generateInternalIR*(runtime: Runtime) = runtime.ir.newModule("BALI_RESOLVEFIELD") - runtime.vm.registerBuiltin("BALI_RESOLVEFIELD_INTERNAL", + runtime.vm.registerBuiltin( + "BALI_RESOLVEFIELD_INTERNAL", proc(op: Operation) = let ident = runtime.vm.registers.callArgs.pop() index = uint(&getInt(runtime.vm.registers.callArgs.pop())) storeAt = uint(&getInt(runtime.vm.registers.callArgs.pop())) - let atom = runtime.vm.stack[index] # FIXME: weird bug with mirage, `get` returns a NULL atom. + let atom = runtime.vm.stack[index] + # FIXME: weird bug with mirage, `get` returns a NULL atom. if atom.kind != Object: debug "runtime: atom is not an object, returning null." @@ -580,12 +629,13 @@ proc generateInternalIR*(runtime: Runtime) = return if not atom.objFields.contains(&ident.getStr()): - debug "runtime: atom does not have any field \"" & &ident.getStr() & "\"; returning null." + debug "runtime: atom does not have any field \"" & &ident.getStr() & + "\"; returning null." runtime.vm.addAtom(obj(), storeAt) return - + let value = atom.objValues[atom.objFields[&ident.getStr()]] - runtime.vm.addAtom(value, storeAt) + runtime.vm.addAtom(value, storeAt), ) runtime.ir.call("BALI_RESOLVEFIELD_INTERNAL") @@ -608,7 +658,7 @@ proc run*(runtime: Runtime) = runtime.generateIRForScope(runtime.ast.scopes[0]) let source = runtime.ir.emit() - + privateAccess(PulsarInterpreter) # modern problems require modern solutions runtime.vm.tokenizer = tokenizer.newTokenizer(source) @@ -624,13 +674,13 @@ proc run*(runtime: Runtime) = info "interpreter: passing over execution to VM" runtime.vm.run() -proc newRuntime*(file: string, ast: AST, opts: InterpreterOpts = default(InterpreterOpts)): Runtime {.inline.} = +proc newRuntime*( + file: string, ast: AST, opts: InterpreterOpts = default(InterpreterOpts) +): Runtime {.inline.} = Runtime( ast: ast, clauses: @[], - ir: newIRGenerator( - "bali-" & $sha256(file).toHex() - ), + ir: newIRGenerator("bali-" & $sha256(file).toHex()), vm: newPulsarInterpreter(""), - opts: opts + opts: opts, ) diff --git a/src/bali/runtime/normalize.nim b/src/bali/runtime/normalize.nim index 1a740bc..d3cfd6b 100644 --- a/src/bali/runtime/normalize.nim +++ b/src/bali/runtime/normalize.nim @@ -4,7 +4,7 @@ proc normalizeIRName*(name: string): string = for i, c in name: case c - of {'a'..'z'}, {'A'..'Z'}: + of {'a' .. 'z'}, {'A' .. 'Z'}: buffer &= c of '.': buffer &= "dot" @@ -36,6 +36,10 @@ proc normalizeIRName*(name: string): string = of '@': buffer &= "at" else: - raise newException(ValueError, "Found invalid character in buffer during normalization (pos " & $i & "): '" & c & "' in " & name) + raise newException( + ValueError, + "Found invalid character in buffer during normalization (pos " & $i & "): '" & c & + "' in " & name, + ) buffer diff --git a/src/bali/runtime/objects.nim b/src/bali/runtime/objects.nim index adbad27..065fe1b 100644 --- a/src/bali/runtime/objects.nim +++ b/src/bali/runtime/objects.nim @@ -4,9 +4,8 @@ import mirage/atom import mirage/ir/generator import bali/internal/sugar -type - BaliObject* = object - fields*: Table[string, MAtom] +type BaliObject* = object + fields*: Table[string, MAtom] proc `[]=`*(obj: var BaliObject, key: string, atom: MAtom) {.inline.} = obj.fields[key] = atom @@ -21,13 +20,14 @@ proc inject*(obj: BaliObject, pos: uint, ir: IRGenerator): uint = discard ir.loadInt(pos, atom) of String: discard ir.loadStr(pos, atom) - else: unreachable + else: + unreachable pos proc newBaliObject*(fields: openArray[string]): BaliObject {.inline.} = var obj = BaliObject(fields: initTable[string, MAtom]()) - + for field in fields: obj[field] = null() diff --git a/src/bali/stdlib/builtins/base64.nim b/src/bali/stdlib/builtins/base64.nim index add82c9..36e5541 100644 --- a/src/bali/stdlib/builtins/base64.nim +++ b/src/bali/stdlib/builtins/base64.nim @@ -19,17 +19,18 @@ else: proc generateStdIr*(vm: PulsarInterpreter, generator: IRGenerator) = info "builtins.base64: generating IR interfaces" - + # atob # Decode a base64 encoded string generator.newModule("atob") - vm.registerBuiltin("BALI_ATOB", + vm.registerBuiltin( + "BALI_ATOB", proc(op: Operation) = if vm.registers.callArgs.len < 1: typeError(vm, "atob: At least 1 argument required, but only 0 passed") return - template decodeError = + template decodeError() = warn "atob: failed to decode string: " & exc.msg typeError(vm, "atob: String contains an invalid character") return @@ -41,25 +42,29 @@ proc generateStdIr*(vm: PulsarInterpreter, generator: IRGenerator) = try: vm.registers.retVal = some(str decode(strVal)) except Base64DecodeError as exc: - when not defined(baliUseStdBase64): decodeError + when not defined(baliUseStdBase64): + decodeError except ValueError as exc: - when defined(baliUseStdBase64): decodeError + when defined(baliUseStdBase64): + decodeError + , ) generator.call("BALI_ATOB") # btoa # Encode a string into Base64 data generator.newModule("btoa") - vm.registerBuiltin("BALI_BTOA", + vm.registerBuiltin( + "BALI_BTOA", proc(op: Operation) = if vm.registers.callArgs.len < 1: typeError(vm, "btoa: At least 1 argument required, but only 0 passed") return - let + let value = vm.RequireObjectCoercible(vm.registers.callArgs[0]) str = vm.ToString(value) - vm.registers.retVal = some(str encode(str)) + vm.registers.retVal = some(str encode(str)), ) generator.call("BALI_BTOA") diff --git a/src/bali/stdlib/builtins/parse_int.nim b/src/bali/stdlib/builtins/parse_int.nim index 243efe1..4eff9ca 100644 --- a/src/bali/stdlib/builtins/parse_int.nim +++ b/src/bali/stdlib/builtins/parse_int.nim @@ -15,26 +15,31 @@ proc parseIntGenerateStdIr*(vm: PulsarInterpreter, generator: IRGenerator) = # parseInt # The parseInt() function parses a string argument and returns an integer of the specified radix (the base in mathematical numeral systems). generator.newModule("parseInt") - vm.registerBuiltin("BALI_PARSEINT", + vm.registerBuiltin( + "BALI_PARSEINT", proc(op: Operation) = if vm.registers.callArgs.len < 1: vm.registers.retVal = some floating NaN return - let - inputString = vm.registers.callArgs[0] # 1. Let inputString be ? ToString(string). - value = vm.trimString(inputString, TrimMode.Left) # 2. Let S be ! TrimString(inputString, start). + let + inputString = vm.registers.callArgs[0] + # 1. Let inputString be ? ToString(string). + value = vm.trimString(inputString, TrimMode.Left) + # 2. Let S be ! TrimString(inputString, start). # FIXME: should we interpret the rest as according to the spec or should we leave it to the Nim standard library? It seems to work as intended... - radix = if vm.registers.callArgs.len > 1: # 8. If R ≠ 0, then - vm.registers.callArgs[1].getInt() - else: - # We don't remove the first two chars from the beginning of the string as `parseInt` in std/strutils does it itself when the radix is set to 16. - if value.startsWith("0x"): # 10. a. If the length of S is at least 2 and the first two code units of S are either "0x" or "0X", then - some(16) # ii. Set R to 16. - else: # 9. Else, - some(10) # a. Set R to 10. - + radix = + if vm.registers.callArgs.len > 1: # 8. If R ≠ 0, then + vm.registers.callArgs[1].getInt() + else: + # We don't remove the first two chars from the beginning of the string as `parseInt` in std/strutils does it itself when the radix is set to 16. + if value.startsWith("0x"): + # 10. a. If the length of S is at least 2 and the first two code units of S are either "0x" or "0X", then + some(16) # ii. Set R to 16. + else: # 9. Else, + some(10) # a. Set R to 10. + try: vm.registers.retVal = some( case &radix @@ -54,6 +59,6 @@ proc parseIntGenerateStdIr*(vm: PulsarInterpreter, generator: IRGenerator) = ) except ValueError as exc: warn "builtins.parse_int(" & $value & "): " & exc.msg & " (radix=" & $radix & ')' - vm.registers.retVal = some floating NaN + vm.registers.retVal = some floating NaN, ) generator.call("BALI_PARSEINT") diff --git a/src/bali/stdlib/builtins/test262.nim b/src/bali/stdlib/builtins/test262.nim index c2a892c..a813db1 100644 --- a/src/bali/stdlib/builtins/test262.nim +++ b/src/bali/stdlib/builtins/test262.nim @@ -16,23 +16,25 @@ proc test262Error*(vm: PulsarInterpreter, msg: string) = proc generateStdIr*(vm: PulsarInterpreter, generator: IRGenerator) = info "builtins.test262: generating IR interfaces" - + # $DONOTEVALUATE (stub) generator.newModule(normalizeIRName "$DONOTEVALUATE") - vm.registerBuiltin("TESTS_DONOTEVALUATE", + vm.registerBuiltin( + "TESTS_DONOTEVALUATE", proc(op: Operation) = - return + return , ) generator.call("TESTS_DONOTEVALUATE") # assert.sameValue generator.newModule(normalizeIRName "assert.sameValue") - vm.registerBuiltin("TESTS_ASSERTSAMEVALUE", + vm.registerBuiltin( + "TESTS_ASSERTSAMEVALUE", proc(op: Operation) = - template no = + template no() = vm.test262Error("Assert.sameValue(): " & a.crush() & " != " & b.crush()) - - template yes = + + template yes() = info "Assert.sameValue(): passed test! (" & a.crush() & " == " & b.crush() & ')' discard @@ -42,23 +44,17 @@ proc generateStdIr*(vm: PulsarInterpreter, generator: IRGenerator) = if a.kind != b.kind: no - + case a.kind of Integer: - if a.getInt() == b.getInt(): - yes - else: - no + if a.getInt() == b.getInt(): yes else: no of UnsignedInt: - if a.getUint() == b.getUint(): - yes - else: no + if a.getUint() == b.getUint(): yes else: no of String: - if a.getStr() == b.getStr(): - yes - else: - no - of Null: yes - else: no + if a.getStr() == b.getStr(): yes else: no + of Null: + yes + else: + no, ) generator.call("TESTS_ASSERTSAMEVALUE") diff --git a/src/bali/stdlib/console.nim b/src/bali/stdlib/console.nim index e92232e..29a433d 100644 --- a/src/bali/stdlib/console.nim +++ b/src/bali/stdlib/console.nim @@ -20,9 +20,8 @@ type ConsoleDelegate* = proc(level: ConsoleLevel, msg: string) -const - DefaultConsoleDelegate* = proc(level: ConsoleLevel, msg: string) = - echo $level & ": " & msg +const DefaultConsoleDelegate* = proc(level: ConsoleLevel, msg: string) = + echo $level & ": " & msg var delegate: ConsoleDelegate = DefaultConsoleDelegate @@ -40,54 +39,59 @@ proc console(vm: PulsarInterpreter, level: ConsoleLevel) {.inline.} = proc consoleLogIR*(vm: PulsarInterpreter, generator: IRGenerator) = # generate binding interface - + # console.log # Perform Logger("log", data). generator.newModule(normalizeIRName "console.log") - vm.registerBuiltin("BALI_CONSOLELOG", + vm.registerBuiltin( + "BALI_CONSOLELOG", proc(op: Operation) = - console(vm, ConsoleLevel.Log) + console(vm, ConsoleLevel.Log), ) generator.call("BALI_CONSOLELOG") - + # console.warn # Perform Logger("warn", data). generator.newModule(normalizeIRName "console.warn") - vm.registerBuiltin("BALI_CONSOLEWARN", + vm.registerBuiltin( + "BALI_CONSOLEWARN", proc(op: Operation) = - console(vm, ConsoleLevel.Warn) + console(vm, ConsoleLevel.Warn), ) generator.call("BALI_CONSOLEWARN") - + # console.info # Perform Logger("info", data). generator.newModule(normalizeIRName "console.info") - vm.registerBuiltin("BALI_CONSOLEINFO", + vm.registerBuiltin( + "BALI_CONSOLEINFO", proc(op: Operation) = - console(vm, ConsoleLevel.Info) + console(vm, ConsoleLevel.Info), ) generator.call("BALI_CONSOLEINFO") - + # console.error # Perform Logger("error", data). generator.newModule(normalizeIRName "console.error") - vm.registerBuiltin("BALI_CONSOLEERROR", + vm.registerBuiltin( + "BALI_CONSOLEERROR", proc(op: Operation) = - console(vm, ConsoleLevel.Error) + console(vm, ConsoleLevel.Error), ) generator.call("BALI_CONSOLEERROR") - + # console.debug # Perform Logger("debug", data). generator.newModule(normalizeIRName "console.debug") - vm.registerBuiltin("BALI_CONSOLEDEBUG", + vm.registerBuiltin( + "BALI_CONSOLEDEBUG", proc(op: Operation) = - console(vm, ConsoleLevel.Debug) + console(vm, ConsoleLevel.Debug), ) generator.call("BALI_CONSOLEDEBUG") @@ -96,5 +100,5 @@ proc consoleLogIR*(vm: PulsarInterpreter, generator: IRGenerator) = proc generateStdIR*(vm: PulsarInterpreter, generator: IRGenerator) = info "console: generating IR interfaces" - + consoleLogIR(vm, generator) diff --git a/src/bali/stdlib/errors.nim b/src/bali/stdlib/errors.nim index adfb5ff..f189a3d 100644 --- a/src/bali/stdlib/errors.nim +++ b/src/bali/stdlib/errors.nim @@ -7,9 +7,8 @@ import mirage/runtime/prelude import bali/runtime/normalize import bali/internal/sugar -type - JSException* = ref object of RuntimeException - name: string = "" +type JSException* = ref object of RuntimeException + name: string = "" proc generateMessage*(exc: JSException, err: string): string = var msg = "Uncaught " @@ -20,7 +19,7 @@ proc generateMessage*(exc: JSException, err: string): string = msg & err proc jsException*(msg: string): JSException {.inline.} = - var exc = JSException() + var exc = JSException() exc.message = exc.generateMessage(msg) exc @@ -34,18 +33,15 @@ proc logTracebackAndDie*(vm: PulsarInterpreter) = proc typeError*(vm: PulsarInterpreter, message: string) {.inline.} = ## Meant for other Bali stdlib methods to use. - vm.throw( - jsException("TypeError: " & message) - ) + vm.throw(jsException("TypeError: " & message)) vm.logTracebackAndDie() proc generateStdIr*(vm: PulsarInterpreter, ir: IRGenerator) = info "errors: generate IR interface" - vm.registerBuiltin("BALI_THROWERROR", + vm.registerBuiltin( + "BALI_THROWERROR", proc(op: Operation) = - vm.throw( - jsException(&vm.registers.callArgs[0].getStr()) - ) - vm.logTracebackAndDie() + vm.throw(jsException(&vm.registers.callArgs[0].getStr())) + vm.logTracebackAndDie(), ) diff --git a/src/bali/stdlib/math.nim b/src/bali/stdlib/math.nim index d53373a..2af8824 100644 --- a/src/bali/stdlib/math.nim +++ b/src/bali/stdlib/math.nim @@ -10,10 +10,10 @@ import pretty, librng, librng/generator privateAccess(RNG) -const - rawAlgo {.strdefine: "BaliRNGAlgorithm".} = "xoroshiro128" +const rawAlgo {.strdefine: "BaliRNGAlgorithm".} = "xoroshiro128" -let Algorithm = case rawAlgo +let Algorithm = + case rawAlgo of "xoroshiro128": Xoroshiro128 of "xoroshiro128pp": Xoroshiro128PlusPlus of "xoroshiro128ss": Xoroshiro128StarStar @@ -22,156 +22,169 @@ let Algorithm = case rawAlgo of "pcg": PCG of "lehmer": Lehmer64 of "splitmix": Splitmix64 - else: - Xoroshiro128 + else: Xoroshiro128 # Global RNG source var rng = newRNG(algo = Algorithm) proc generateStdIr*(vm: PulsarInterpreter, generator: IRGenerator) = info "math: generating IR interfaces" - + # Math.random # WARN: Do not use this for cryptography! This uses one of eight highly predictable pseudo-random # number generation algorithms that librng implements! generator.newModule(normalizeIRName "Math.random") - vm.registerBuiltin("BALI_MATHRANDOM", + vm.registerBuiltin( + "BALI_MATHRANDOM", proc(op: Operation) = let value = float64(rng.generator.next()) / 1.8446744073709552e+19'f64 - vm.registers.retVal = some floating value + vm.registers.retVal = some floating value, ) generator.call("BALI_MATHRANDOM") # Math.pow generator.newModule(normalizeIRName "Math.pow") - vm.registerBuiltin("BALI_MATHPOW", + vm.registerBuiltin( + "BALI_MATHPOW", proc(op: Operation) = let value = vm.ToNumber(vm.registers.callArgs[0]) exponent = vm.ToNumber(vm.registers.callArgs[1]) - - vm.registers.retVal = some floating pow(value, exponent) + + vm.registers.retVal = some floating pow(value, exponent), ) generator.call("BALI_MATHPOW") # Math.cos generator.newModule(normalizeIRName "Math.cos") - vm.registerBuiltin("BALI_MATHCOS", + vm.registerBuiltin( + "BALI_MATHCOS", proc(op: Operation) = let value = vm.ToNumber(vm.registers.callArgs[0]) - - vm.registers.retVal = some floating cos(value) + + vm.registers.retVal = some floating cos(value), ) generator.call("BALI_MATHCOS") # Math.sqrt generator.newModule(normalizeIRName "Math.sqrt") - vm.registerBuiltin("BALI_MATHSQRT", + vm.registerBuiltin( + "BALI_MATHSQRT", proc(op: Operation) = let value = vm.ToNumber(vm.registers.callArgs[0]) - vm.registers.retVal = some floating sqrt(value) + vm.registers.retVal = some floating sqrt(value), ) generator.call("BALI_MATHSQRT") # Math.tanh generator.newModule(normalizeIRName "Math.tanh") - vm.registerBuiltin("BALI_MATHTANH", + vm.registerBuiltin( + "BALI_MATHTANH", proc(op: Operation) = let value = vm.ToNumber(vm.registers.callArgs[0]) - vm.registers.retVal = some floating tanh(value) + vm.registers.retVal = some floating tanh(value), ) generator.call("BALI_MATHTANH") # Math.sin generator.newModule(normalizeIRName "Math.sin") - vm.registerBuiltin("BALI_MATHSIN", + vm.registerBuiltin( + "BALI_MATHSIN", proc(op: Operation) = let value = vm.ToNumber(vm.registers.callArgs[0]) - vm.registers.retVal = some floating sin(value) + vm.registers.retVal = some floating sin(value), ) generator.call("BALI_MATHSIN") # Math.sinh generator.newModule(normalizeIRName "Math.sinh") - vm.registerBuiltin("BALI_MATHSINH", + vm.registerBuiltin( + "BALI_MATHSINH", proc(op: Operation) = let value = vm.ToNumber(vm.registers.callArgs[0]) - vm.registers.retVal = some floating sinh(value) + vm.registers.retVal = some floating sinh(value), ) generator.call("BALI_MATHSINH") - + # Math.tan generator.newModule(normalizeIRName "Math.tan") - vm.registerBuiltin("BALI_MATHTAN", + vm.registerBuiltin( + "BALI_MATHTAN", proc(op: Operation) = let value = vm.ToNumber(vm.registers.callArgs[0]) - vm.registers.retVal = some floating tan(value) + vm.registers.retVal = some floating tan(value), ) generator.call("BALI_MATHTAN") # Math.trunc generator.newModule(normalizeIRName "Math.trunc") - vm.registerBuiltin("BALI_MATHTRUNC", + vm.registerBuiltin( + "BALI_MATHTRUNC", proc(op: Operation) = let value = vm.ToNumber(vm.registers.callArgs[0]) - vm.registers.retVal = some floating trunc(value) + vm.registers.retVal = some floating trunc(value), ) generator.call("BALI_MATHTRUNC") # Math.floor generator.newModule(normalizeIRName "Math.floor") - vm.registerBuiltin("BALI_MATHFLOOR", + vm.registerBuiltin( + "BALI_MATHFLOOR", proc(op: Operation) = let value = vm.ToNumber(vm.registers.callArgs[0]) - vm.registers.retVal = some floating floor(value) + vm.registers.retVal = some floating floor(value), ) generator.call("BALI_MATHFLOOR") # Math.ceil generator.newModule(normalizeIRName "Math.ceil") - vm.registerBuiltin("BALI_MATHCEIL", + vm.registerBuiltin( + "BALI_MATHCEIL", proc(op: Operation) = let value = vm.ToNumber(vm.registers.callArgs[0]) - vm.registers.retVal = some floating ceil(value) + vm.registers.retVal = some floating ceil(value), ) generator.call("BALI_MATHCEIL") # Math.cbrt generator.newModule(normalizeIRName "Math.cbrt") - vm.registerBuiltin("BALI_MATHCBRT", + vm.registerBuiltin( + "BALI_MATHCBRT", proc(op: Operation) = let value = vm.ToNumber(vm.registers.callArgs[0]) - vm.registers.retVal = some floating cbrt(value) + vm.registers.retVal = some floating cbrt(value), ) generator.call("BALI_MATHCBRT") # Math.log generator.newModule(normalizeIRName "Math.max") - vm.registerBuiltin("BALI_MATHMAX", + vm.registerBuiltin( + "BALI_MATHMAX", proc(op: Operation) = - let + let a = vm.ToNumber(vm.registers.callArgs[0]) b = vm.ToNumber(vm.registers.callArgs[1]) - vm.registers.retVal = some floating max(a, b) + vm.registers.retVal = some floating max(a, b), ) generator.call("BALI_MATHMAX") # Math.abs generator.newModule(normalizeIRName "Math.abs") - vm.registerBuiltin("BALI_MATHABS", + vm.registerBuiltin( + "BALI_MATHABS", proc(op: Operation) = let value = vm.ToNumber(vm.registers.callArgs[0]) - vm.registers.retVal = some floating abs(value) + vm.registers.retVal = some floating abs(value), ) generator.call("BALI_MATHABS") diff --git a/src/bali/stdlib/uri.nim b/src/bali/stdlib/uri.nim index 08024b2..8d4ea35 100644 --- a/src/bali/stdlib/uri.nim +++ b/src/bali/stdlib/uri.nim @@ -16,33 +16,36 @@ proc transposeUrlToObject(parsed: URL, url: var MAtom, source: MAtom) = when not defined(danger): assert url.kind == Object, $url.kind - url.objFields["hostname"] = 0#str parsed.hostname() - url.objFields["pathname"] = 1#str parsed.path() - url.objFields["port"] = 2#integer parsed.port() - url.objFields["protocol"] = 3#str parsed.scheme() - url.objFields["search"] = 4#str parsed.query() - url.objFields["host"] = 5#str parsed.hostname() - url.objFields["href"] = 6#source + url.objFields["hostname"] = 0 #str parsed.hostname() + url.objFields["pathname"] = 1 #str parsed.path() + url.objFields["port"] = 2 #integer parsed.port() + url.objFields["protocol"] = 3 #str parsed.scheme() + url.objFields["search"] = 4 #str parsed.query() + url.objFields["host"] = 5 #str parsed.hostname() + url.objFields["href"] = 6 #source url.objFields["origin"] = 7 url.objFields["hash"] = 8 - url.objValues = @[ - str parsed.hostname(), - str parsed.path(), - integer parsed.port().int, - str parsed.scheme(), - str parsed.query(), - str parsed.hostname(), - source, - str(parsed.scheme() & "://" & parsed.hostname() & ":" & $parsed.port()), - (if parsed.fragment().len > 0: str '#' & parsed.fragment() else: str newString(0)) - ] + url.objValues = + @[ + str parsed.hostname(), + str parsed.path(), + integer parsed.port().int, + str parsed.scheme(), + str parsed.query(), + str parsed.hostname(), + source, + str(parsed.scheme() & "://" & parsed.hostname() & ":" & $parsed.port()), + (if parsed.fragment().len > 0: str '#' & parsed.fragment() + else: str newString(0)), + ] proc generateStdIR*(vm: PulsarInterpreter, ir: IRGenerator) = info "url: generating IR interfaces" # `new URL()` syntax - vm.registerBuiltin("BALI_CONSTRUCTOR_URL", + vm.registerBuiltin( + "BALI_CONSTRUCTOR_URL", proc(op: Operation) = let source = if vm.registers.callArgs.len > 0: @@ -51,51 +54,58 @@ proc generateStdIR*(vm: PulsarInterpreter, ir: IRGenerator) = null() if source.kind != String: - vm.typeError("URL constructor: " & ToString(vm, source) & " is not a valid URL.") + vm.typeError( + "URL constructor: " & ToString(vm, source) & " is not a valid URL." + ) return - let parsed = try: - parser.parse(ToString(vm, source)) - except URLParseError as pError: - debug "url: encountered parse error whilst parsing url: " & &source.getStr() & ": " & pError.msg - debug "url: this is a constructor, so a TypeError will be thrown." - vm.typeError(pError.msg) - newURL("", "", "", "") - + let parsed = + try: + parser.parse(ToString(vm, source)) + except URLParseError as pError: + debug "url: encountered parse error whilst parsing url: " & &source.getStr() & + ": " & pError.msg + debug "url: this is a constructor, so a TypeError will be thrown." + vm.typeError(pError.msg) + newURL("", "", "", "") + if parsed.scheme().len < 1: return var url = obj() transposeUrlToObject(parsed, url, source) - - vm.registers.retVal = some(url) + + vm.registers.retVal = some(url), ) - + ir.newModule(normalizeIRName "URL.parse") - vm.registerBuiltin("BALI_URLPARSE", + vm.registerBuiltin( + "BALI_URLPARSE", proc(op: Operation) = if vm.registers.callArgs.len < 1: vm.registers.retVal = some null() return let source = vm.registers.callArgs[0] - + if source.kind != String: vm.registers.retVal = some null() return - var parsed = try: - parser.parse(&source.getStr()) - except URLParseError as exc: - debug "url: encountered parse error whilst parsing url: " & &source.getStr() & ": " & exc.msg - debug "url: this is the function variant, so no error will be thrown." - URL() + var parsed = + try: + parser.parse(&source.getStr()) + except URLParseError as exc: + debug "url: encountered parse error whilst parsing url: " & &source.getStr() & + ": " & exc.msg + debug "url: this is the function variant, so no error will be thrown." + URL() # allocate object var url = obj() transposeUrlToObject(parsed, url, source) - vm.registers.retVal = some(url) + vm.registers.retVal = some(url), ) ir.call("BALI_URLPARSE") diff --git a/tests/common.nim b/tests/common.nim index 29c8049..3e3f7cb 100644 --- a/tests/common.nim +++ b/tests/common.nim @@ -1,7 +1,7 @@ import std/[logging] import pretty, colored_logger -proc enableLogging* {.inline.} = +proc enableLogging*() {.inline.} = addHandler newColoredLogger() export pretty diff --git a/tests/config.nims b/tests/config.nims index 3bb69f8..80091ff 100644 --- a/tests/config.nims +++ b/tests/config.nims @@ -1 +1 @@ -switch("path", "$projectDir/../src") \ No newline at end of file +switch("path", "$projectDir/../src") diff --git a/tests/parser/t001.nim b/tests/parser/t001.nim index aa78f04..01f0b2a 100644 --- a/tests/parser/t001.nim +++ b/tests/parser/t001.nim @@ -4,14 +4,16 @@ import pretty import ../common enableLogging() -let parser = newParser(""" +let parser = newParser( + """ function main() { let x = "e" let y = "this is truly a moment" } main() -""") +""" +) let ast = parser.parse() print parser.errors diff --git a/tests/parser/t002.nim b/tests/parser/t002.nim index 8643811..25e462c 100644 --- a/tests/parser/t002.nim +++ b/tests/parser/t002.nim @@ -4,11 +4,7 @@ import pretty import ../common enableLogging() -let parser = newParser( - readFile( - paramStr(1) - ) -) +let parser = newParser(readFile(paramStr(1))) let ast = parser.parse() print parser.errors diff --git a/tests/runtime/t001.nim b/tests/runtime/t001.nim index 6406968..4a6d003 100644 --- a/tests/runtime/t001.nim +++ b/tests/runtime/t001.nim @@ -16,15 +16,9 @@ let fn = function( @[ createImmutVal("x", integer(32)), # equivalent to `const x = 32` createImmutVal("y", integer(32)), - ifCond( - lhs = "x", rhs = "y", ecEqual - ), - call("console.log", - @[ - atomArg integer 32 - ] - ) - ] + ifCond(lhs = "x", rhs = "y", ecEqual), + call("console.log", @[atomArg integer 32]), + ], ) program &= fn diff --git a/tests/runtime/t003.nim b/tests/runtime/t003.nim index bc26831..e4af959 100644 --- a/tests/runtime/t003.nim +++ b/tests/runtime/t003.nim @@ -5,7 +5,8 @@ import pretty import ../common enableLogging() -let parser = newParser(""" +let parser = newParser( + """ function main() { let x = "e" let y = "this is truly a moment" @@ -13,7 +14,8 @@ function main() { } main() -""") +""" +) let ast = parser.parse() print parser.errors diff --git a/tests/runtime/t004.nim b/tests/runtime/t004.nim index 9571f2d..abc6996 100644 --- a/tests/runtime/t004.nim +++ b/tests/runtime/t004.nim @@ -5,9 +5,7 @@ import pretty import ../common enableLogging() -let parser = newParser( - readFile paramStr 1 -) +let parser = newParser(readFile paramStr 1) let ast = parser.parse() print parser.errors diff --git a/tests/runtime/t005.nim b/tests/runtime/t005.nim index f039fb9..7cb65f6 100644 --- a/tests/runtime/t005.nim +++ b/tests/runtime/t005.nim @@ -10,15 +10,7 @@ var program = newAST() var doMathsArgs: PositionedArguments doMathsArgs.pushIdent("x") -let fn = function( - "do_maths", - @[ - call("console.log", - doMathsArgs - ) - ], - @["x"] -) +let fn = function("do_maths", @[call("console.log", doMathsArgs)], @["x"]) program.appendFunctionToCurrentScope(fn) var args: PositionedArguments @@ -27,7 +19,7 @@ args.pushImmExpr( kind: BinaryOp, binLeft: atomHolder(integer(13)), binRight: atomHolder(integer(37)), - op: BinaryOperation.Add + op: BinaryOperation.Add, ) ) diff --git a/tests/runtime/thing.nim b/tests/runtime/thing.nim index ceeefb3..d0cd4be 100644 --- a/tests/runtime/thing.nim +++ b/tests/runtime/thing.nim @@ -9,15 +9,11 @@ var ast = newAST() var args: PositionedArguments args.pushAtom(str "https://github.com") -ast.appendToCurrentScope( - callAndStoreMut("url", call("URL.parse", args)) -) +ast.appendToCurrentScope(callAndStoreMut("url", call("URL.parse", args))) var args2: PositionedArguments args2.pushIdent("url") -ast.appendToCurrentScope( - call("console.log", args2) -) +ast.appendToCurrentScope(call("console.log", args2)) let runtime = newRuntime("t003.js", ast) runtime.run() diff --git a/tests/string_trim.nim b/tests/string_trim.nim index ffb55ef..46752b0 100644 --- a/tests/string_trim.nim +++ b/tests/string_trim.nim @@ -1,7 +1,6 @@ import std/[strutils, unittest] import bali/internal/trim_string - suite "TrimString( string, where )": test "trim leading whitespace": check " 32".internalTrim(strutils.Whitespace, TrimMode.Left) == "32" @@ -9,4 +8,5 @@ suite "TrimString( string, where )": test "trim ending whitespace": check "32 ".internalTrim(strutils.Whitespace, TrimMode.Right) == "32" - check ":^) ".internalTrim(strutils.Whitespace, TrimMode.Right) == ":^)" + check ":^) ".internalTrim(strutils.Whitespace, TrimMode.Right) == + ":^)" diff --git a/tests/test262.nim b/tests/test262.nim index c7614e5..52aff8d 100644 --- a/tests/test262.nim +++ b/tests/test262.nim @@ -8,7 +8,7 @@ const BASE_DIR = "test262/test" proc execJS(file: string): bool = execCmd("./balde run " & file & " --test262") == 0 -proc main {.inline.} = +proc main() {.inline.} = addHandler(newColoredLogger()) addHandler(newFileLogger("test262.log")) @@ -32,16 +32,16 @@ Commands: let head = paramStr(2) var filesToExec = 0 - + if not dirExists(BASE_DIR / head): error "Invalid testing category: " & head quit(1) - var - successful, failed, skipped: seq[string] + var successful, failed, skipped: seq[string] for file in walkDirRec(BASE_DIR / head): - if not fileExists(file): continue + if not fileExists(file): + continue if not file.endsWith(".js"): skipped &= file continue @@ -56,11 +56,11 @@ Commands: warn "Test for `" & file & "` has failed." failed &= file continue - + let successPercentage = (successful.len / filesToExec) * 100f failedPercentage = (failed.len / filesToExec) * 100f - + if failed.len > 0: info "The following tests have failed:" for i, fail in failed: @@ -69,19 +69,22 @@ Commands: break echo " * " & fail - + if paramCount() > 1 and paramStr(2) == "json": - echo $(%* { - "total": $filesToExec, - "successful": $successful.len, - "skipped": $skipped.len, - "failed": $failed.len, - "successful_percentage": $successPercentage - }) + echo $( + %*{ + "total": $filesToExec, + "successful": $successful.len, + "skipped": $skipped.len, + "failed": $failed.len, + "successful_percentage": $successPercentage, + } + ) else: info "Total tests: " & $filesToExec info "Successful tests: " & $successPercentage & "% (" & $successful.len & ')' info "Skipped tests: " & $skipped info "Failed tests: " & $failedPercentage & "% (" & $failed.len & ')' - -when isMainModule: main() + +when isMainModule: + main() diff --git a/tests/tokenizer/t001.nim b/tests/tokenizer/t001.nim index 1160024..351d513 100644 --- a/tests/tokenizer/t001.nim +++ b/tests/tokenizer/t001.nim @@ -4,10 +4,6 @@ import ../common enableLogging() var tokenizer = newTokenizer(readFile paramStr 1) -let tokens = tokenizer.tokenize( - TokenizerOpts( - ignoreWhitespace: true - ) -) +let tokens = tokenizer.tokenize(TokenizerOpts(ignoreWhitespace: true)) print tokens