diff --git a/src/compiler.ts b/src/compiler.ts index 369b414..8fc2b2b 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -74,6 +74,7 @@ export const BytecodeDefault: ParseTreeTable = { not: (out, node) => (visitParseNode(out, node.expr), pushBytecode(out, node.token, { type: 'not' })), evalfunc: (out, node) => (node.typeArgs.map(x => writeMeta(out, x)), visitAll(out, node.args), pushBytecode(out, node.token, { type: "evalfunc", func: node.func })), + concurrency: (out, node) => (visitAll(out, node.fns), pushBytecode(out, node.token, { type: 'concurrency', count: node.fns.length })), note: (out, node) => { if (node.expr instanceof ParseCall) { @@ -122,7 +123,8 @@ export const BytecodeDefault: ParseTreeTable = { visitAll(out, node.typeArgs) visitAll(out, node.args); if (node.left instanceof ParseValue) { // Internal desugar results in a fixed value sometimes - pushBytecode(out, node.token, { type: "callobj", callable: node.left.value, count: node.args.length, tcount: node.typeArgs.length }) + visitParseNode(out, node.left) + pushBytecode(out, node.token, { type: "callobj", count: node.args.length, tcount: node.typeArgs.length }) return; } if (node.left instanceof ParseIdentifier) { @@ -137,6 +139,11 @@ export const BytecodeDefault: ParseTreeTable = { compilerAssert(false, "Call with field not implemented yet", { node }) return; } + if (node.left instanceof ParseFunction) { + visitParseNode(out, node.left) + pushBytecode(out, node.token, { type: "callobj", count: node.args.length, tcount: node.typeArgs.length }) + return; + } compilerAssert(false, "Call with non-identifier not implemented yet", { left: node.left}) }, postcall: (out, node) => { @@ -298,6 +305,7 @@ export const BytecodeSecondOrder: ParseTreeTable = { }, evalfunc: (out, node) => (node.typeArgs.map(x => writeMeta(out, x)), visitAll(out, node.args), pushBytecode(out, node.token, { type: "evalfunc", func: node.func })), + concurrency: (out, node) => (visitAll(out, node.fns), pushBytecode(out, node.token, { type: 'concurrency', count: node.fns.length })), note: (out, node) => { if (node.expr instanceof ParseCall) { @@ -586,9 +594,10 @@ export function createBytecodeVmAndExecuteTask(ctx: TaskContext, subCompilerStat return ( TaskDef(executeVmTask, { vm }) .mapRejected(error => { - if (error.info) { - if (!(error.info as any).location) (error.info as any).location = vm.location; - (error.info as any).subCompilerState = subCompilerState + const info = error.info as any + if (info) { + if (!info.location) info.location = vm.location; + if (!info.subCompilerState) info.subCompilerState = subCompilerState } return error }) @@ -889,6 +898,11 @@ const instructions: InstructionMapping = { vm.stack.push(new IfAst(resultType, vm.location, cond, trueBody, falseBody)) }, evalfunc: (vm, { func }) => { return func(vm) }, + concurrency: (vm, { count }) => { + const values = popValues(vm, count).reverse() + const fnctx: CompilerFunctionCallContext = { location: vm.location, compilerState: vm.context.subCompilerState, resultAst: undefined, typeCheckResult: undefined } + return Task.concurrency(values.map(x => createCallAstFromValue(fnctx, x, [], []))) + }, listast: (vm, { count }) => { const values = expectAsts(popValues(vm, count)) const elementType = getCommonType(values.map(x => x.type)) @@ -1032,6 +1046,7 @@ const instructions: InstructionMapping = { return TaskDef(resolveScope, vm.scope, name).chainFn((task, binding) => { compilerAssert(binding instanceof Binding, "Expected binding got $binding", { binding }) const ast = propagatedLiteralAst(expectAst(popStack(vm))) + compilerAssert(binding.type === ast.type, "Type mismatch got $got expected $expected", { got: ast.type, expected: binding.type }) vm.stack.push(new SetAst(VoidType, vm.location, binding, ast)) return Task.success() }); @@ -1220,7 +1235,8 @@ const instructions: InstructionMapping = { }) ) }, - callobj: (vm, { callable, count, tcount }) => { + callobj: (vm, { count, tcount }) => { + const callable = popStack(vm) const values = popValues(vm, count); const typeArgs = popValues(vm, tcount || 0); return TaskDef(callFunctionFromValueTask, vm, callable, typeArgs, values) @@ -1333,7 +1349,10 @@ function executeVmTask(ctx: TaskContext, { vm } : { vm: Vm }, p: void): Task { const decl: ParserFunctionDecl = { - id: undefined, debugName: ``, token: createAnonymousToken(''), functionMetaName: null, name: null, typeParams: [], params: [], keywords: [], anonymous: true, returnType: null, body: null, annotations: [], variadic: false @@ -1724,7 +1742,6 @@ const createInitializerFunctionTask = (ctx: TaskContext) => { const createEntryFunctionTask = (ctx: TaskContext) => { const decl: ParserFunctionDecl = { - id: undefined, debugName: ``, token: createAnonymousToken(''), functionMetaName: null, name: null, typeParams: [], params: [], keywords: [], anonymous: true, returnType: null, body: null, annotations: [], variadic: false diff --git a/src/compiler_functions.ts b/src/compiler_functions.ts index 2b20849..cf05923 100644 --- a/src/compiler_functions.ts +++ b/src/compiler_functions.ts @@ -5,18 +5,20 @@ import { Task, TaskDef, Unit } from "./tasks"; export const insertFunctionDefinition = (compilerState: GlobalCompilerState, decl: ParserFunctionDecl) => { - if (decl.id !== undefined) return compilerState.functionDefinitions[decl.id]; + const existing = compilerState.functionDefinitionsByDeclaration.get(decl) + if (existing) return existing - decl.id = compilerState.functionDefinitions.length; + const id = compilerState.functionDefinitions.length; const keywords = decl.keywords.map(x => x instanceof ParseNote ? x.expr.token.value : x.token.value) const inline = !!decl.anonymous || keywords.includes('inline') const funcDef = new FunctionDefinition( - decl.id, decl.debugName, + id, decl.debugName, decl.name, decl.typeParams, decl.params, decl.returnType, decl.body, inline, decl.annotations) funcDef.variadic = decl.variadic funcDef.keywords.push(...keywords) + compilerState.functionDefinitionsByDeclaration.set(decl, funcDef) if (funcDef.keywords.includes("external")) { compilerAssert(decl.name, "Expected name") diff --git a/src/compiler_iterator.ts b/src/compiler_iterator.ts index 8198644..6911da8 100644 --- a/src/compiler_iterator.ts +++ b/src/compiler_iterator.ts @@ -1,6 +1,6 @@ import { BytecodeSecondOrder, compileFunctionPrototype, getCommonType, getOperatorTable, loadModule, popStack, popValues, propagateLiteralType, propagatedLiteralAst, pushBytecode, resolveScope, unknownToAst, visitParseNode } from "./compiler" import { compileExportedFunctionTask, createCallAstFromValue, createCallAstFromValueAndPushValue, createMethodCall, insertFunctionDefinition } from "./compiler_functions" -import { Ast, BytecodeWriter, Closure, CompiledClass, ConstructorAst, ExternalFunction, FieldAst, FreshBindingToken, ParameterizedType, ParseBlock, ParseBytecode, ParseCall, ParseCompilerIden, ParseConstructor, ParseElse, ParseExpand, ParseFor, ParseFunction, ParseIdentifier, ParseIf, ParseLet, ParseList, ParseListComp, ParseMeta, ParseNode, ParseNumber, ParseOpEq, ParseOperator, ParseQuote, ParseSet, ParseSlice, ParseStatements, ParseSubscript, ParseValue, ParseWhile, Scope, SourceLocation, SubCompilerState, Token, TupleTypeConstructor, VoidType, compilerAssert, createAnonymousParserFunctionDecl, createAnonymousToken, ParseFreshIden, ParseAnd, ParseFold, ParseForExpr, ParseWhileExpr, Module, pushSubCompilerState, createScope, TaskContext, CompilerError, AstType, OperatorAst, CompilerFunction, CallAst, RawPointerType, SubscriptAst, IntType, expectType, SetSubscriptAst, ParserFunctionParameter, FunctionType, Binding, StringType, ValueFieldAst, LetAst, BindingAst, createStatements, StringAst, FloatType, DoubleType, CompilerFunctionCallContext, Vm, expectAst, NumberAst, Type, UserCallAst, hashValues, NeverType, IfAst, BoolType, VoidAst, LoopObject, CompileTimeObjectType, u64Type, FunctionDefinition, ParserFunctionDecl, StatementsAst, isTypeScalar, IntLiteralType, FloatLiteralType, isAst, isType, isTypeCheckError, InterleaveAst, ContinueInterAst, CompTimeObjAst, ParseEvalFunc, SetAst, DefaultConsAst, WhileAst, BoolAst, isArray, ExpansionSelector, ParseNote, ExpansionCompilerState, ParseBoolean, ParseOr, ParseBreak, filterNotNull, ParseTuple, ParseNot, ParseLetConst } from "./defs" +import { Ast, BytecodeWriter, Closure, CompiledClass, ConstructorAst, ExternalFunction, FieldAst, FreshBindingToken, ParameterizedType, ParseBlock, ParseBytecode, ParseCall, ParseCompilerIden, ParseConstructor, ParseElse, ParseExpand, ParseFor, ParseFunction, ParseIdentifier, ParseIf, ParseLet, ParseList, ParseListComp, ParseMeta, ParseNode, ParseNumber, ParseOpEq, ParseOperator, ParseQuote, ParseSet, ParseSlice, ParseStatements, ParseSubscript, ParseValue, ParseWhile, Scope, SourceLocation, SubCompilerState, Token, TupleTypeConstructor, VoidType, compilerAssert, createAnonymousParserFunctionDecl, createAnonymousToken, ParseFreshIden, ParseAnd, ParseFold, ParseForExpr, ParseWhileExpr, Module, pushSubCompilerState, createScope, TaskContext, CompilerError, AstType, OperatorAst, CompilerFunction, CallAst, RawPointerType, SubscriptAst, IntType, expectType, SetSubscriptAst, ParserFunctionParameter, FunctionType, Binding, StringType, ValueFieldAst, LetAst, BindingAst, createStatements, StringAst, FloatType, DoubleType, CompilerFunctionCallContext, Vm, expectAst, NumberAst, Type, UserCallAst, hashValues, NeverType, IfAst, BoolType, VoidAst, LoopObject, CompileTimeObjectType, u64Type, FunctionDefinition, ParserFunctionDecl, StatementsAst, isTypeScalar, IntLiteralType, FloatLiteralType, isAst, isType, isTypeCheckError, InterleaveAst, ContinueInterAst, CompTimeObjAst, ParseEvalFunc, SetAst, DefaultConsAst, WhileAst, BoolAst, isArray, ExpansionSelector, ParseNote, ExpansionCompilerState, ParseBoolean, ParseOr, ParseBreak, filterNotNull, ParseTuple, ParseNot, ParseLetConst, ParseConcurrency, ParseCompTime } from "./defs" import { Event, Task, TaskDef, isTask } from "./tasks" @@ -158,15 +158,38 @@ const createConstructor = (vm: Vm, constructor: ArrayConstructorCompiler) => { }) ) } -const arrayConstructorFinish = (vm: Vm, constructor: ArrayConstructorCompiler) => { + +const arrayConstructorFinish = new ExternalFunction('arrayConstructorFinish', VoidType, (ctx, values) => { + const [constructor] = values; + compilerAssert(constructor instanceof ArrayConstructorCompiler, "Expected array constructor", { constructor }) compilerAssert(constructor.arrayConstructor, "Expected array constructor", { constructor }) - const location = vm.location const binding = constructor.constructorBinding compilerAssert(binding, "Expected list binding", { constructor }) - const let_ = new LetAst(VoidType, location, binding, constructor.arrayConstructor) - const bindingAst = new BindingAst(binding.type, location, binding) - vm.stack.push(createStatements(location, [let_, ...constructor.calls, bindingAst])) -} + const let_ = new LetAst(VoidType, ctx.location, binding, constructor.arrayConstructor) + const bindingAst = new BindingAst(binding.type, ctx.location, binding) + return createStatements(ctx.location, [let_, ...constructor.calls, bindingAst]) +}) + +const appendValuePartialFn = (() => { + const token = createAnonymousToken('') + const consIdenParam = new ParseIdentifier(createAnonymousToken('cons')) + const exprParam = new ParseIdentifier(createAnonymousToken('expr')) + + const exprQuote = new ParseQuote(token, exprParam) + const iden = new ParseFreshIden(token, new FreshBindingToken('elem')) + const let_ = new ParseLet(token, iden, null, exprQuote) + const call = new ParseCall(token, new ParseValue(token, arrayConstructorTypeCheck), [consIdenParam, iden], []) + const call2 = new ParseCall(token, new ParseValue(token, arrayConstructorCreateAppend), [consIdenParam, iden], []) + const call3 = new ParseCall(token, new ParseValue(token, arrayConstructorAddAppendCall), [consIdenParam, call2], []) + const meta_ = new ParseMeta(token, new ParseStatements(token, [let_, call, call3])) + const decl = createAnonymousParserFunctionDecl('appendValue', token, [], meta_) + + const params: ParserFunctionParameter[] = [ + { name: consIdenParam, storage: null, type: null }, + { name: exprParam, storage: null, type: null } + ] + return createAnonymousParserFunctionDecl('appendValuePartial', token, params, new ParseFunction(token, decl)) +})() export const listConstructorSugar = (out: BytecodeWriter, node: ParseList) => { const listConstructorIden = new ParseFreshIden(node.token, new FreshBindingToken('list')) @@ -191,35 +214,12 @@ export const listConstructorSugar = (out: BytecodeWriter, node: ParseList) => { const fn = createAnonymousParserFunctionDecl('appendIterator', node.token, [], meta_) return new ParseFunction(node.token, fn) } else { - const exprQuote = new ParseQuote(node.token, expr) - const iden = new ParseFreshIden(node.token, new FreshBindingToken('elem')) - const let_ = new ParseLet(node.token, iden, null, exprQuote) - const call = new ParseCall(node.token, new ParseValue(node.token, arrayConstructorTypeCheck), [listConstructorIden, iden], []) - const call2 = new ParseCall(node.token, new ParseValue(node.token, arrayConstructorCreateAppend), [listConstructorIden, iden], []) - const call3 = new ParseCall(node.token, new ParseValue(node.token, arrayConstructorAddAppendCall), [listConstructorIden, call2], []) - const meta_ = new ParseMeta(node.token, new ParseStatements(node.token, [let_, call, call3])) - - const fn = createAnonymousParserFunctionDecl('appendValue', node.token, [], meta_) - return new ParseFunction(node.token, fn) + return new ParseCall(node.token, new ParseFunction(node.token, appendValuePartialFn), [listConstructorIden, new ParseQuote(node.token, expr)], []) } }).filter(x => x) as ParseFunction[] - - const compilation = (vm: Vm) => { - const values = popValues(vm, fns.length).reverse() - const constructor = popStack(vm) - compilerAssert(constructor instanceof ArrayConstructorCompiler, "Expected array constructor", { constructor }) - - const fnctx: CompilerFunctionCallContext = { location: node.token.location, compilerState: vm.context.subCompilerState, resultAst: undefined, typeCheckResult: undefined } - const compileFns = values.map((fn, i) => createCallAstFromValue(fnctx, fn, [], [])) - const compileFnsTask = Task.concurrency([...compileFns]) - return compileFnsTask.chainFn((task, _) => { - compilerAssert(constructor instanceof ArrayConstructorCompiler, "Expected array constructor", { constructor }) - arrayConstructorFinish(vm, constructor) - return Task.success() - }) - } - visitParseNode(out, new ParseEvalFunc(node.token, compilation, [...fns], [listConstructorIden])) + visitParseNode(out, new ParseCompTime(node.token, new ParseConcurrency(node.token, fns))) + visitParseNode(out, new ParseMeta(node.token, new ParseCall(node.token, new ParseValue(node.token, arrayConstructorFinish), [listConstructorIden], []))) } @@ -730,6 +730,84 @@ export const expandFuncLastSugar = (out: BytecodeWriter, noteNode: ParseNote, ar const value = new ParseStatements(node.token, [let_, reduce, iden]) visitParseNode(out, value) } + +export class DeferredLetBinding { + type: Type + binding: Binding | null + letAst: LetAst + constructor() {} +} + +const createDeferObject = new ExternalFunction('createDeferObject', CompileTimeObjectType, (ctx, values) => { + return new CompTimeObjAst(CompileTimeObjectType, ctx.location, new DeferredLetBinding()) +}) +const deferAssignSet = new ExternalFunction('deferAssignSet', VoidType, (ctx, values) => { + let [value, defer] = values + if (defer instanceof CompTimeObjAst) defer = defer.value + compilerAssert(defer instanceof DeferredLetBinding, "Expected deferred let binding", { defer }) + compilerAssert(isAst(value), "Expected ast", { value, defer }) + compilerAssert(value instanceof LetAst, "Expected let ast", { value, defer }) + Object.assign(defer, { letAst: value, type: value.type, binding: value.binding }) +}) +const deferToSetAst = new ExternalFunction('deferToSetAst', VoidType, (ctx, values) => { + let [value, defer] = values + if (defer instanceof CompTimeObjAst) defer = defer.value + compilerAssert(isAst(value), "Expected ast", { value, defer }) + compilerAssert(defer instanceof DeferredLetBinding, "Expected deferred let binding", { defer }) + compilerAssert(defer.binding, "Expected binding", { defer }) + return new SetAst(VoidType, ctx.location, defer.binding, value) +}) +const deferToBindingAst = new ExternalFunction('deferToBindingAst', VoidType, (ctx, values) => { + let [stmts, defer] = values + if (defer instanceof CompTimeObjAst) defer = defer.value + compilerAssert(defer instanceof DeferredLetBinding, "Expected deferred let binding", { defer }) + compilerAssert(isAst(stmts), "Expected ast", { stmts, defer }) + const binding = defer.binding + compilerAssert(binding, "Expected binding", { defer }) + const bindingAst = new BindingAst(binding.type, ctx.location, binding) + return createStatements(ctx.location, [defer.letAst, stmts, bindingAst]) +}) + +const createFreshLet = new ExternalFunction('createFreshLet', VoidType, (ctx, values) => { + let [value] = values + compilerAssert(isAst(value), "Expected ast", { value }) + const binding = new Binding("defer", value.type) + return new LetAst(binding.type, ctx.location, binding, value) +}) + +const createDefaultFromType = new ExternalFunction('createDefaultFromType', VoidType, (ctx, values) => { + let [type] = values + compilerAssert(isType(type), "Expected type", { type }) + return new DefaultConsAst(type, ctx.location) +}) + +const typeOf = new ExternalFunction('typeOf', VoidType, (ctx, values) => { + let [value] = values + compilerAssert(isAst(value), "Expected ast", { value }) + return value.type +}) + +const deferredHelperSetter = (token: Token, deferIden: ParseFreshIden, result: ParseNode) => { + const typeOf_ = new ParseCall(token, new ParseValue(token, typeOf), [new ParseQuote(token, result)], []) + const default_ = new ParseCall(token, + new ParseValue(token, createDefaultFromType), [typeOf_], []) + const toLet_ = new ParseCall(token, + new ParseValue(token, createFreshLet), [default_], []) + const tcResult = new ParseCall(createAnonymousToken(''), + new ParseValue(token, deferAssignSet), [toLet_, deferIden], []) + const call_ = new ParseCall(createAnonymousToken(''), + new ParseValue(token, deferToSetAst), [new ParseQuote(token, result), deferIden], []) + return new ParseStatements(token, [new ParseCompTime(token, tcResult), new ParseMeta(token, call_),]) +} + +const deferredHelperResult = (token: Token, deferIden: ParseFreshIden, original: ParseNode) => { + const letobj = new ParseLetConst(token, deferIden, new ParseCall(createAnonymousToken(''), new ParseValue(token, createDeferObject), [], [])) + const stmts = new ParseStatements(token, [letobj, original]) + const call_ = new ParseCall(createAnonymousToken(''), new ParseValue(token, deferToBindingAst), [ + new ParseQuote(createAnonymousToken(''), stmts), new ParseQuote(createAnonymousToken(''), deferIden)], []) + return new ParseMeta(createAnonymousToken(''), call_) +} + export const expandFuncFirstSugar = (out: BytecodeWriter, noteNode: ParseNote, args: ParseNode[]) => { compilerAssert(!out.state.expansion, "Already in expansion state") const node = args[0] @@ -739,16 +817,12 @@ export const expandFuncFirstSugar = (out: BytecodeWriter, noteNode: ParseNote, a compilerAssert(!expansion.fold, "Fold not supported in this context") - const iden = new ParseFreshIden(node.token, new FreshBindingToken('first')) - const set = new ParseSet(node.token, iden, result) - - expansion.loopBodyNode = new ParseStatements(node.token, [set, new ParseBreak(node.token, expansion.breakIden, null)]) - - // TODO: Only supports numbers at the moment + const deferIden = new ParseFreshIden(node.token, new FreshBindingToken('defer')) + const break_ = new ParseBreak(node.token, expansion.breakIden, null) + const deferSet_ = deferredHelperSetter(node.token, deferIden, result) + expansion.loopBodyNode = new ParseStatements(node.token, [deferSet_, break_]) const reduce = compileExpansionToParseNode(out, expansion, node) - const let_ = new ParseLet(node.token, iden, null, new ParseNumber(createAnonymousToken('0'))) - const value = new ParseStatements(node.token, [let_, reduce, iden]) - visitParseNode(out, value) + visitParseNode(out, deferredHelperResult(node.token, deferIden, reduce)) } export const expandFuncMinSugar = (out: BytecodeWriter, noteNode: ParseNote, args: ParseNode[]) => { compilerAssert(!out.state.expansion, "Already in expansion state") diff --git a/src/defs.ts b/src/defs.ts index 09f9e29..2759052 100644 --- a/src/defs.ts +++ b/src/defs.ts @@ -72,7 +72,7 @@ export type ParserFunctionParameter = { } // These are reference types that id will be filled in later. export type ParserFunctionDecl = { - id: number | undefined, debugName: string, anonymous?: boolean, + debugName: string, anonymous?: boolean, token: Token, functionMetaName: ParseIdentifier | null, name: ParseIdentifier | null, typeParams: ParseNode[], params: ParserFunctionParameter[], returnType: ParseNode | null, body: ParseNode | null, keywords: ParseNode[], @@ -173,6 +173,7 @@ export class ParseFreshIden extends ParseNodeType { key = 'freshiden' as cons export class ParseConstructor extends ParseNodeType { key = 'constructor' as const; constructor(public token: Token, public type: ParseNode, public args: ParseNode[]) { super();} } export class ParseCompilerIden extends ParseNodeType { key = 'compileriden' as const; constructor(public token: Token, public value: string) { super();} } export class ParseEvalFunc extends ParseNodeType { key = 'evalfunc' as const; constructor(public token: Token, public func: (vm: Vm) => void | Task, public args: ParseNode[], public typeArgs: ParseNode[]) { super();} } +export class ParseConcurrency extends ParseNodeType { key = 'concurrency' as const; constructor(public token: Token, public fns: ParseNode[]) { super();} } export type ParseNode = ParseStatements | ParseLet | ParseSet | ParseOperator | ParseIdentifier | ParseNumber | ParseMeta | ParseCompTime | ParseLetConst | ParseCall | ParseList | ParseOr | ParseAnd | @@ -180,7 +181,8 @@ export type ParseNode = ParseStatements | ParseLet | ParseSet | ParseOperator | ParseOpEq | ParseWhile | ParseWhileExpr | ParseForExpr | ParseNot | ParseField | ParseExpand | ParseListComp | ParseDict | ParsePostCall | ParseSymbol | ParseNote | ParseSlice | ParseSubscript | ParseTuple | ParseClass | ParseNil | ParseBoolean | ParseElse | ParseMetaIf | ParseMetaFor | ParseMetaWhile | ParseBlock | ParseImport | - ParseCompilerIden | ParseValue | ParseConstructor | ParseQuote | ParseBytecode | ParseFreshIden | ParseFold | ParseNamedArg | ParseEvalFunc + ParseCompilerIden | ParseValue | ParseConstructor | ParseQuote | ParseBytecode | ParseFreshIden | ParseFold | + ParseNamedArg | ParseEvalFunc | ParseConcurrency // Void types mean that in secondOrder compilation, the AST doesn't return an AST export const isParseVoid = (ast: ParseNode) => ast.key == 'letconst' || ast.key === 'function' || ast.key === 'class' || ast.key === 'comptime' || ast.key === 'metawhile'; @@ -202,7 +204,7 @@ export type BytecodeInstr = { type: 'dictast', count: number } | { type: 'closure', id: number } | { type: 'call', name: string, count: number, tcount: number } | - { type: 'callobj', callable: unknown, count: number, tcount: number } | + { type: 'callobj', count: number, tcount: number } | { type: 'compilerfn', name: string, count: number, tcount: number } | { type: 'return', r: boolean } | { type: 'namedarg' } | @@ -244,6 +246,7 @@ export type BytecodeInstr = { type: 'jump', address: number } | { type: 'jumpf', address: number } | { type: 'evalfunc', func: (vm: Vm) => void | Task } | + { type: 'concurrency', count: number } | { type: 'halt' } @@ -860,6 +863,7 @@ export type Logger = { log: (...args: any[]) => void } export type GlobalCompilerState = { compiledFunctions: Map; functionDefinitions: FunctionDefinition[], + functionDefinitionsByDeclaration: Map, classDefinitions: ClassDefinition[], moduleLoader: ModuleLoader methods: WeakMap, @@ -930,6 +934,7 @@ export const createDefaultGlobalCompiler = () => { const globalCompiler: GlobalCompilerState = { compiledFunctions: new Map(), functionDefinitions: [], + functionDefinitionsByDeclaration: new Map(), classDefinitions: [], allWaitingEvents: [], globalLets: [], @@ -1014,7 +1019,7 @@ export function bytecodeToString(bytecodeProgram: BytecodeProgram) { const instr = (instr: BytecodeInstr) => { const { type, ...args } = instr; const values = Object.entries(args) - .map(([k, v]) => `${k}: ${typeof v === 'function' ? '' : v}`) + .map(([k, v]) => `${k}: ${typeof v === 'function' ? '' : typeof v === 'string' ? v : Inspect(v)}`) .join(", "); return `${type.padStart("beginblockast".length, " ")} ${values}`; }; diff --git a/tests/fixtures/iterator_expansion.rad b/tests/fixtures/iterator_expansion.rad index 994a3c0..3d9e576 100644 --- a/tests/fixtures/iterator_expansion.rad +++ b/tests/fixtures/iterator_expansion.rad @@ -201,10 +201,16 @@ fn test_last(): fn test_first(): - numbers := [40, 20, 10, 32, 12, 3124] + numbers := [40.0, 20, 10, 32, 12, 3124] + x := @first(numbers[:]) print(x) - assert(x == 40) + + people := [Person(10), Person(20), Person(30), Person(40), Person(50)] + p := @first(people[1:]) + + print(p.age) + # assert(x == 40) fn test_range(): rng := Range(10, 20) @@ -329,6 +335,13 @@ fn test_iterator_to_array(): print(arr[:]) ... +fn test_array(): + x := 0.2 + arr := [ 3, 1, 1] + # assert(@sum(arr[:]) == 43545640) + print(arr[:]) ... + + fn main(): test_fold() test_shorthand() @@ -353,3 +366,4 @@ fn main(): test_flatmap() test_custom_iterator() test_iterator_to_array() + test_array()