From e6875810c5d55a972e516c94bdd9eca1a4af766b Mon Sep 17 00:00:00 2001 From: Peachpit Date: Mon, 17 Feb 2025 17:32:20 -0800 Subject: [PATCH] Fix function sharing --- hub/hub.hub | 6 +- source/compiler/compfcall.go | 26 ++-- source/compiler/compiler.go | 189 +++++++++++++++--------------- source/initializer/getters.go | 4 +- source/initializer/gohandler.go | 1 - source/initializer/initializer.go | 103 ++++++++++------ source/parser/function_table.go | 12 +- source/parser/parser.go | 2 +- source/parser/types.go | 27 +---- source/settings/settings.go | 4 +- 10 files changed, 181 insertions(+), 193 deletions(-) diff --git a/hub/hub.hub b/hub/hub.hub index 086dd32e..96bd42f2 100644 --- a/hub/hub.hub +++ b/hub/hub.hub @@ -7,11 +7,9 @@ Database = struct(driver DatabaseDrivers, name, host string, port int, username, var -allServices = map(`temp`::`C:\Users\owner\Pipefish\examples\temp.pf`, - .. `hub`::`hub/hub.hub`, - .. `imp`::`C:\Users\owner\Pipefish\source\compiler\test-files\import_test.pf`) +allServices = map(`hub`::`hub/hub.hub`) -currentService string? = `imp` +currentService string? = NULL isLive = true diff --git a/source/compiler/compfcall.go b/source/compiler/compfcall.go index 85f3c102..2a051705 100644 --- a/source/compiler/compfcall.go +++ b/source/compiler/compfcall.go @@ -73,14 +73,14 @@ func (cp *Compiler) createFunctionCall(argCompiler *Compiler, node ast.Callable, backtrackList[i] = DUMMY if i < cp.P.FunctionForest[node.GetToken().Literal].RefCount { // It might be a reference variable if arg.GetToken().Type != token.IDENT { - cp.P.Throw("comp/ref/ident", arg.GetToken()) + cp.Throw("comp/ref/ident", arg.GetToken()) return AltType(values.COMPILE_TIME_ERROR), false } var v *variable v, ok := env.GetVar(arg.GetToken().Literal) if !ok { if ac == REPL { - cp.P.Throw("comp/ref/var", arg.GetToken()) + cp.Throw("comp/ref/var", arg.GetToken()) return AltType(values.COMPILE_TIME_ERROR), false } else { // We must be in a command. We can create a local variable. cp.Reserve(values.UNDEFINED_TYPE, nil, node.GetToken()) @@ -116,7 +116,7 @@ func (cp *Compiler) createFunctionCall(argCompiler *Compiler, node ast.Callable, cst = cst && cstI b.valLocs[i] = cp.That() if b.types[i].(AlternateType).isOnly(values.ERROR) { - cp.P.Throw("comp/error/arg", arg.GetToken()) + cp.Throw("comp/error/arg", arg.GetToken()) return AltType(values.COMPILE_TIME_ERROR), false } if b.types[i].(AlternateType).Contains(values.ERROR) { // IMPORTANT --- find out if the ret statement is going to cause a problem with thunks as it did below before I fixed it. @@ -134,7 +134,7 @@ func (cp *Compiler) createFunctionCall(argCompiler *Compiler, node ast.Callable, cp.cmP("Returned from initial call into generateNewArgument", b.tok) cp.put(vm.Asgm, b.outLoc) if returnTypes.isOnly(values.ERROR) && node.GetToken().Literal != "error" { - cp.P.Throw("comp/types", b.tok, b.tok.Literal, b.types.describeWithPotentialInfix(cp.Vm, b.tok.Literal)) + cp.Throw("comp/types", b.tok, b.tok.Literal, b.types.describeWithPotentialInfix(cp.Vm, b.tok.Literal)) } for _, v := range backtrackList { if v != DUMMY { @@ -277,8 +277,8 @@ func (cp *Compiler) generateBranch(b *bindle) AlternateType { varargsSlurpingTupleTypeCheck := bkGoto(DUMMY) if needsLowerBranch && !acceptingTuple { cp.cmP("Overlap is partial: "+overlap.describe(cp.Vm), b.tok) - cp.cmP("Accepted any types are "+acceptedSingleTypes.describe(cp.Vm), b.tok) - cp.cmP("Emitting type comparisons for any types.", b.tok) + cp.cmP("Accepted single types are "+acceptedSingleTypes.describe(cp.Vm), b.tok) + cp.cmP("Emitting type comparisons for single types.", b.tok) // Then we need to generate a conditional. Which one exactly depends on whether we're looking at a any, a tuple, or both. switch len(acceptedSingleTypes) { case 0: @@ -322,7 +322,7 @@ func (cp *Compiler) generateBranch(b *bindle) AlternateType { typesFromGoingAcross = cp.generateMoveAlongBranchViaTupleElement(&newBindle) } case len(overlap): - cp.cmP("Nothing but any types", b.tok) + cp.cmP("Nothing but single types", b.tok) if acceptedTypes.Contains(values.TUPLE) { cp.reserveError("vm/types/b", b.tok) for _, loc := range b.valLocs { @@ -333,17 +333,17 @@ func (cp *Compiler) generateBranch(b *bindle) AlternateType { cp.Emit(vm.Asgm, b.outLoc, cp.That()) return AltType(values.ERROR) } - cp.cmP("Going across branch consuming any value.", b.tok) + cp.cmP("Going across branch consuming single value.", b.tok) typesFromGoingAcross = cp.generateMoveAlongBranchViaSingleOrTupleValue(&newBindle) default: skipElse := bkGoto(DUMMY) - cp.cmP("Mix of any and tuple types.", b.tok) + cp.cmP("Mix of single and tuple types.", b.tok) if acceptedTypes.Contains(values.TUPLE) { cp.cmP("Type is tuple. Generating branch to consume tuple.", b.tok) typesFromTuples = cp.generateMoveAlongBranchViaSingleOrTupleValue(&newBindle) } else { singleCheck := cp.vmIf(vm.Qsnq, b.valLocs[b.argNo]) - cp.cmP("Generating branch to check out any values.", b.tok) + cp.cmP("Generating branch to check out single values.", b.tok) typesFromSingles = cp.generateMoveAlongBranchViaSingleOrTupleValue(&newBindle) skipElse = cp.vmGoTo() cp.vmComeFrom(singleCheck) @@ -576,7 +576,7 @@ func (cp *Compiler) seekFunctionCall(b *bindle) AlternateType { cp.Emit(vm.Call, args...) // TODO --- find out from the sig whether this should be CalT.args := append([]uint32{DUMMY, DUMMY, DUMMY}, valLocs...) cp.Emit(vm.Asgm, b.outLoc, DUMMY) b.override = true - return cp.rtnTypesToTypeScheme(cp.P.MakeAbstractSigFromStringSig(branch.Node.Fn.NameRets)) + return cp.rtnTypesToTypeScheme(branch.Node.Fn.Compiler.(*Compiler).P.MakeAbstractSigFromStringSig(branch.Node.Fn.NameRets)) } if fNo >= uint32(len(resolvingCompiler.Fns)) && cp == resolvingCompiler { cp.cmP("Undefined function. We're doing recursion!", b.tok) @@ -587,12 +587,12 @@ func (cp *Compiler) seekFunctionCall(b *bindle) AlternateType { cp.Emit(vm.Rpop) cp.Emit(vm.Asgm, b.outLoc, DUMMY) // We don't know where the function's output will be yet. b.override = true // We can't do constant folding on a dummy function call. - return cp.rtnTypesToTypeScheme(cp.P.MakeAbstractSigFromStringSig(branch.Node.Fn.NameRets)) + return cp.rtnTypesToTypeScheme(branch.Node.Fn.Compiler.(*Compiler).P.MakeAbstractSigFromStringSig(branch.Node.Fn.NameRets)) } F := resolvingCompiler.Fns[fNo] if (b.access == REPL || b.libcall) && F.Private { cp.cmP("REPL trying to access private function. Returning error.", b.tok) - cp.P.Throw("comp/private", b.tok) + cp.Throw("comp/private", b.tok) return AltType(values.COMPILE_TIME_ERROR) } // Deal with the case where the function is a builtin. diff --git a/source/compiler/compiler.go b/source/compiler/compiler.go index a9895087..fcdfb669 100644 --- a/source/compiler/compiler.go +++ b/source/compiler/compiler.go @@ -195,7 +195,7 @@ NodeTypeSwitch: cp.Cm("Assignment from REPL or in 'cmd' section", node.GetToken()) sig, err := cp.P.RecursivelySlurpSignature(node.Left, "*inferred*") if err != nil { - cp.P.Throw("comp/assign/lhs/a", node.Left.GetToken()) + cp.Throw("comp/assign/lhs/a", node.Left.GetToken()) break NodeTypeSwitch } cp.Cm("Assignment signature is "+text.Emph(sig.String()), &node.Token) @@ -219,7 +219,7 @@ NodeTypeSwitch: cp.Cm("Inferring the type of a variable "+text.Emph(pair.VarName)+" already defined ", &node.Token) if sig.GetVarType(i) != "*inferred*" { // Then as we can't change the type of an existing variable, we must check that we're defining it the same way. if !Equals(v.types, cp.GetAlternateTypeFromTypeName(sig[i].VarType)) { - cp.P.Throw("comp/assign/type/b", node.GetToken(), pair.VarName) + cp.Throw("comp/assign/type/b", node.GetToken(), pair.VarName) break NodeTypeSwitch } } @@ -230,15 +230,15 @@ NodeTypeSwitch: } if v.access == GLOBAL_CONSTANT_PRIVATE || v.access == LOCAL_VARIABLE_THUNK || v.access == LOCAL_CONSTANT || v.access == LOCAL_FUNCTION_CONSTANT || v.access == VERY_LOCAL_CONSTANT || v.access == VERY_LOCAL_VARIABLE || v.access == FUNCTION_ARGUMENT || v.access == LOCAL_FUNCTION_THUNK { - cp.P.Throw("comp/assign/immutable", node.Left.GetToken(), pair.VarName) + cp.Throw("comp/assign/immutable", node.Left.GetToken(), pair.VarName) break NodeTypeSwitch } if ac == REPL && (ALL_PRIVATE_ACCESS.Contains(v.access)) { - cp.P.Throw("comp/assign/private", node.Left.GetToken(), pair.VarName) + cp.Throw("comp/assign/private", node.Left.GetToken(), pair.VarName) break NodeTypeSwitch } if ac == REPL && (ALL_CONSTANT_ACCESS.Contains(v.access)) { - cp.P.Throw("comp/assign/const", node.Left.GetToken(), pair.VarName) + cp.Throw("comp/assign/const", node.Left.GetToken(), pair.VarName) break NodeTypeSwitch } if v.access == GLOBAL_VARIABLE_PUBLIC { @@ -247,7 +247,7 @@ NodeTypeSwitch: } else { // The variable doesn't already exist. cp.Cm("Assignment creating local variable "+text.Emph(sig.String())+".", &node.Token) if ac == REPL { - cp.P.Throw("comp/assign/repl", node.Left.GetToken(), pair.VarName) + cp.Throw("comp/assign/repl", node.Left.GetToken(), pair.VarName) break NodeTypeSwitch } cp.Reserve(values.UNDEFINED_TYPE, DUMMY, node.GetToken()) @@ -273,7 +273,7 @@ NodeTypeSwitch: cp.vmComeFrom(rhsIsError, typeCheckFailed) break NodeTypeSwitch case *ast.Bling: - cp.P.Throw("comp/bling/wut", node.GetToken()) + cp.Throw("comp/bling/wut", node.GetToken()) break case *ast.BooleanLiteral: cp.Reserve(values.BOOL, node.Value, node.GetToken()) @@ -330,7 +330,7 @@ NodeTypeSwitch: enumElement, ok := enumCompiler.EnumElements[node.Value] if ok { if cp.Vm.ConcreteTypeInfo[enumElement.T].IsPrivate() { - cp.P.Throw("comp/private/enum", node.GetToken(), cp.Vm.DescribeType(enumElement.T, vm.LITERAL)) + cp.Throw("comp/private/enum", node.GetToken(), cp.Vm.DescribeType(enumElement.T, vm.LITERAL)) break } cp.Reserve(enumElement.T, enumElement.V, &node.Token) @@ -340,7 +340,7 @@ NodeTypeSwitch: labelNumberLocation, ok := cp.Vm.FieldLabelsInMem[node.Value] if ok { if ac == REPL && cp.Common.LabelIsPrivate[cp.Vm.Mem[labelNumberLocation].V.(int)] { - cp.P.Throw("comp/private/label", node.GetToken()) + cp.Throw("comp/private/label", node.GetToken()) break } cp.put(vm.Asgm, labelNumberLocation) @@ -355,11 +355,11 @@ NodeTypeSwitch: v, ok = env.GetVar(node.Value) } if !ok { - cp.P.Throw("comp/ident/known", node.GetToken(), node.Value) + cp.Throw("comp/ident/known", node.GetToken(), node.Value) break } if (v.access == GLOBAL_CONSTANT_PRIVATE || v.access == GLOBAL_VARIABLE_PRIVATE) && ac == REPL { - cp.P.Throw("comp/ident/private", node.GetToken()) + cp.Throw("comp/ident/private", node.GetToken()) break } if v.access == LOCAL_VARIABLE_THUNK || v.access == LOCAL_FUNCTION_THUNK { @@ -411,7 +411,7 @@ NodeTypeSwitch: rtnTypes = containerType } if indexType.cannotBeACloneOf(cp.Vm, values.INT, values.PAIR) { - cp.P.Throw("comp/index/list", node.GetToken()) + cp.Throw("comp/index/list", node.GetToken()) break } rtnTypes = cp.GetAlternateTypeFromTypeName("any?").Union(AltType(values.ERROR)) @@ -428,7 +428,7 @@ NodeTypeSwitch: break } if indexType.cannotBeACloneOf(cp.Vm, values.INT, values.PAIR) { - cp.P.Throw("comp/index/string", node.GetToken()) + cp.Throw("comp/index/string", node.GetToken()) break } @@ -443,7 +443,7 @@ NodeTypeSwitch: break } if indexType.cannotBeACloneOf(cp.Vm, values.INT, values.PAIR) { - cp.P.Throw("comp/index/tuple", node.GetToken()) + cp.Throw("comp/index/tuple", node.GetToken()) break } rtnTypes = cp.GetAlternateTypeFromTypeName("any?").Union(AltType(values.ERROR)) @@ -454,7 +454,7 @@ NodeTypeSwitch: break } if indexType.cannotBeACloneOf(cp.Vm, values.INT) { - cp.P.Throw("comp/index/pair", node.GetToken()) + cp.Throw("comp/index/pair", node.GetToken()) break } rtnTypes = cp.GetAlternateTypeFromTypeName("any?").Union(AltType(values.ERROR)) @@ -465,7 +465,7 @@ NodeTypeSwitch: break } if indexType.cannotBeACloneOf(cp.Vm, values.INT) { - cp.P.Throw("comp/index/snippet", node.GetToken()) + cp.Throw("comp/index/snippet", node.GetToken()) break } rtnTypes = cp.GetAlternateTypeFromTypeName("any?").Union(AltType(values.ERROR)) @@ -476,7 +476,7 @@ NodeTypeSwitch: break } if indexType.cannotBeACloneOf(cp.Vm, values.INT) { - cp.P.Throw("comp/index/type", node.GetToken()) + cp.Throw("comp/index/type", node.GetToken()) break } if ctrConst { @@ -501,7 +501,7 @@ NodeTypeSwitch: labelName := cp.Vm.Labels[indexNumber] fieldNumber := structInfo.Resolve(indexNumber) if fieldNumber == -1 { - cp.P.Throw("comp/index/struct/a", node.GetToken(), labelName, cp.Vm.DescribeType(structT, vm.LITERAL)) + cp.Throw("comp/index/struct/a", node.GetToken(), labelName, cp.Vm.DescribeType(structT, vm.LITERAL)) break } cp.put(vm.IxZn, container, uint32(fieldNumber)) @@ -517,7 +517,7 @@ NodeTypeSwitch: break } if indexType.IsNoneOf(values.LABEL) { - cp.P.Throw("comp/index/struct/b", node.GetToken()) + cp.Throw("comp/index/struct/b", node.GetToken()) break } } @@ -540,7 +540,7 @@ NodeTypeSwitch: } } if !labelIsPossible { - cp.P.Throw("comp/index/struct/c", node.GetToken()) + cp.Throw("comp/index/struct/c", node.GetToken()) break } if !labelIsCertain { @@ -572,7 +572,7 @@ NodeTypeSwitch: rtnTypes, rtnConst = cp.compileComma(node, ctxt.x()) break } - cp.P.Throw("comp/known/infix", node.GetToken()) + cp.Throw("comp/known/infix", node.GetToken()) break case *ast.IntegerLiteral: cp.Reserve(values.INT, node.Value, node.GetToken()) @@ -582,7 +582,7 @@ NodeTypeSwitch: if node.Operator == "or" { lTypes, lcst := cp.CompileNode(node.Left, ctxt.x()) if !lTypes.Contains(values.BOOL) { - cp.P.Throw("comp/bool/or/left", node.GetToken()) + cp.Throw("comp/bool/or/left", node.GetToken()) break } leftRg := cp.That() @@ -590,7 +590,7 @@ NodeTypeSwitch: skipElse := cp.vmGoTo() rTypes, rcst := cp.CompileNode(node.Right, ctxt.x()) if !rTypes.Contains(values.BOOL) { - cp.P.Throw("comp/bool/or/right", node.GetToken()) + cp.Throw("comp/bool/or/right", node.GetToken()) break } rightRg := cp.That() @@ -602,14 +602,14 @@ NodeTypeSwitch: if node.Operator == "and" { lTypes, lcst := cp.CompileNode(node.Left, ctxt.x()) if !lTypes.Contains(values.BOOL) { - cp.P.Throw("comp/bool/and/left", node.GetToken()) + cp.Throw("comp/bool/and/left", node.GetToken()) break } leftRg := cp.That() checkLhs := cp.vmIf(vm.Qtru, leftRg) rTypes, rcst := cp.CompileNode(node.Right, ctxt.x()) if !rTypes.Contains(values.BOOL) { - cp.P.Throw("comp/bool/and/right", node.GetToken()) + cp.Throw("comp/bool/and/right", node.GetToken()) break } rightRg := cp.That() @@ -631,7 +631,7 @@ NodeTypeSwitch: } lTypes, lcst := cp.CompileNode(node.Left, ctxt.x()) if !lTypes.Contains(values.BOOL) && !lTypes.isOnly(values.ERROR) { - cp.P.Throw("comp/bool/cond/a", node.GetToken()) + cp.Throw("comp/bool/cond/a", node.GetToken()) break } // TODO --- what if it's not *only* bool? @@ -662,7 +662,7 @@ NodeTypeSwitch: cmdRet := lTypes.IsLegalCmdReturn() if !cmdRet && !lTypes.Contains(values.UNSATISFIED_CONDITIONAL) { // TODO --- implement warnings. - // cp.p.Throw("comp/unreachable", node.GetToken()) + // cp.Throw("comp/unreachable", node.GetToken()) // break } var rTypes AlternateType @@ -705,7 +705,7 @@ NodeTypeSwitch: errCheck := bkEarlyReturn(DUMMY) containedTypes, rtnConst = cp.CompileNode(node.List, ctxt.x()) if containedTypes.isOnly(values.ERROR) { - cp.P.Throw("comp/list/err", node.GetToken()) + cp.Throw("comp/list/err", node.GetToken()) break } if containedTypes.Contains(values.ERROR) { @@ -748,7 +748,7 @@ NodeTypeSwitch: lTypes, _ := cp.CompileNode(node.Left, ctxt.x()) if !lTypes.Contains(values.BOOL) { - cp.P.Throw("comp/bool/cond/b", node.GetToken()) + cp.Throw("comp/bool/cond/b", node.GetToken()) break } // TODO --- what if it's not *only* bool? @@ -805,7 +805,7 @@ NodeTypeSwitch: rtnTypes, rtnConst = AltType(values.ERROR, values.BOOL), cst break NodeTypeSwitch default: - cp.P.Throw("comp/bool/not", node.GetToken()) + cp.Throw("comp/bool/not", node.GetToken()) rtnTypes, rtnConst = AltType(values.COMPILE_TIME_ERROR), false break NodeTypeSwitch } @@ -829,12 +829,12 @@ NodeTypeSwitch: case *ast.Identifier: variable, ok := cp.GlobalVars.GetVar(arg.Value) if !ok { - cp.P.Throw("comp/global/global", arg.GetToken()) + cp.Throw("comp/global/global", arg.GetToken()) break NodeTypeSwitch } env.Data[arg.Value] = *variable default: - cp.P.Throw("comp/global/ident", arg.GetToken()) + cp.Throw("comp/global/ident", arg.GetToken()) break NodeTypeSwitch } } @@ -843,7 +843,7 @@ NodeTypeSwitch: } if node.Token.Type == token.BREAK { if !cp.forDataExists() { // Then we're not in a 'for' loop. - cp.P.Throw("comp/break/a", node.GetToken()) + cp.Throw("comp/break/a", node.GetToken()) break NodeTypeSwitch } rtnTypes, rtnConst = cp.CompileNode(node.Args[0], ctxt) @@ -904,7 +904,7 @@ NodeTypeSwitch: cp.Emit(vm.Asgm, cp.That(), errorLoc) default: cp.Cm("Prefix variable cannot be lambda. Throwing error.", node.GetToken()) - cp.P.Throw("comp/apply/func", node.GetToken(), node.Operator) + cp.Throw("comp/apply/func", node.GetToken(), node.Operator) break NodeTypeSwitch } rtnConst = false @@ -917,7 +917,7 @@ NodeTypeSwitch: cp.popRCompiler() break } - cp.P.Throw("comp/known/prefix", node.GetToken()) + cp.Throw("comp/known/prefix", node.GetToken()) break case *ast.RuneLiteral: cp.Reserve(values.RUNE, node.Value, node.GetToken()) @@ -938,14 +938,14 @@ NodeTypeSwitch: resolvingCompiler := cp.getResolvingCompiler(node, node.Namespace, ac) if node.GetToken().Type == token.DOTDOTDOT { if len(node.Args) != 1 { - cp.P.Throw("comp/splat/args", node.GetToken()) + cp.Throw("comp/splat/args", node.GetToken()) break NodeTypeSwitch } var leftTypes AlternateType leftTypes, rtnConst = cp.CompileNode(node.Args[0], ctxt.x()) overlap := leftTypes.intersect(cp.Common.SharedTypenameToTypeList["listlike"]) if len(overlap) == 0 { - cp.P.Throw("comp/splat/type", node.GetToken(), leftTypes) + cp.Throw("comp/splat/type", node.GetToken(), leftTypes) rtnTypes = altType(values.COMPILE_TIME_ERROR) break NodeTypeSwitch } @@ -964,14 +964,14 @@ NodeTypeSwitch: cp.popRCompiler() break } - cp.P.Throw("comp/known/suffix", node.GetToken()) + cp.Throw("comp/known/suffix", node.GetToken()) break case *ast.TryExpression: ident := node.VarName v, exists := env.GetVar(ident) if exists && (v.access == GLOBAL_CONSTANT_PRIVATE || v.access == GLOBAL_CONSTANT_PUBLIC || v.access == GLOBAL_VARIABLE_PRIVATE || v.access == GLOBAL_VARIABLE_PUBLIC || v.access == LOCAL_VARIABLE_THUNK || v.access == LOCAL_FUNCTION_THUNK) { - cp.P.Throw("comp/try/var", node.GetToken()) + cp.Throw("comp/try/var", node.GetToken()) break } var err uint32 @@ -983,7 +983,7 @@ NodeTypeSwitch: } tryTypes, _ := cp.CompileNode(node.Right, ctxt.x()) if tryTypes.IsNoneOf(values.ERROR, values.SUCCESSFUL_VALUE) { - cp.P.Throw("comp/try/return", node.GetToken()) + cp.Throw("comp/try/return", node.GetToken()) break } cp.Emit(vm.Qtyp, cp.That(), uint32(values.ERROR), cp.CodeTop()+4) @@ -1004,7 +1004,7 @@ NodeTypeSwitch: default: abType := resolvingCompiler.P.GetAbstractType(typeName) if (ac == REPL || resolvingCompiler != cp) && cp.IsPrivate(abType) { - cp.P.Throw("comp/private/type", node.GetToken()) + cp.Throw("comp/private/type", node.GetToken()) } cp.Reserve(values.TYPE, abType, node.GetToken()) } @@ -1016,7 +1016,7 @@ NodeTypeSwitch: rtnTypes, rtnConst = resolvingCompiler.createFunctionCall(resolvingCompiler, node, ctxt.x(), len(node.Namespace) > 0) break } - cp.P.Throw("comp/known/unfix", node.GetToken()) // TODO --- can errors like this even arise or must they be caught in the parser? + cp.Throw("comp/known/unfix", node.GetToken()) // TODO --- can errors like this even arise or must they be caught in the parser? break default: panic("Unimplemented node type " + reflect.TypeOf(node).String() + " at line " + strconv.Itoa(node.GetToken().Line) + " of " + node.GetToken().Source) @@ -1024,10 +1024,10 @@ NodeTypeSwitch: // We're done with the typeswitch. We perform some sanity checks to ensure that our functions aren't behaving // like commands or vice versa. if !rtnTypes.IsLegalCmdReturn() && !rtnTypes.IsLegalDefReturn() && !rtnTypes.Contains(values.COMPILE_TIME_ERROR) { - cp.P.Throw("comp/sanity", node.GetToken()) + cp.Throw("comp/sanity", node.GetToken()) } if ac == DEF && !rtnTypes.IsLegalDefReturn() { - cp.P.Throw("comp/fcis", node.GetToken()) + cp.Throw("comp/fcis", node.GetToken()) } if cp.P.ErrorsExist() { return AltType(values.COMPILE_TIME_ERROR), true @@ -1080,13 +1080,13 @@ func (cp *Compiler) checkInferredTypesAgainstContext(rtnTypes AlternateType, typ } typeLengths := lengths(rtnTypes) if !(typeLengths.Contains(-1) || typeLengths.Contains(len(typecheck))) { - cp.P.Throw("comp/return/length", tok, rtnTypes.describe(cp.Vm), typecheck.describe(cp.Vm)) + cp.Throw("comp/return/length", tok, rtnTypes.describe(cp.Vm), typecheck.describe(cp.Vm)) return } for i, ty := range typecheck { intersection := ty.(AlternateType).intersect(typesAtIndex(rtnTypes, i)) if len(intersection) == 0 { - cp.P.Throw("comp/return/types", tok, rtnTypes.without(SimpleType(values.ERROR)).describe(cp.Vm), typecheck.describe(cp.Vm)) + cp.Throw("comp/return/types", tok, rtnTypes.without(SimpleType(values.ERROR)).describe(cp.Vm), typecheck.describe(cp.Vm)) } } } @@ -1098,11 +1098,11 @@ func (cp *Compiler) getResolvingCompiler(node ast.Node, namespace []string, ac C var ok bool resolvingCompiler, ok = resolvingCompiler.Modules[name] if !ok { - cp.P.Throw("comp/namespace/exist", node.GetToken(), name) + cp.Throw("comp/namespace/exist", node.GetToken(), name) return nil } if resolvingCompiler.P.Private && (ac == REPL || len(namespace) > 1) { - cp.P.Throw("comp/namespace/private", node.GetToken(), name) + cp.Throw("comp/namespace/private", node.GetToken(), name) return nil } } @@ -1115,12 +1115,12 @@ func (cp *Compiler) getResolvingCompiler(node ast.Node, namespace []string, ac C func (cp *Compiler) compileComma(node *ast.InfixExpression, ctxt Context) (AlternateType, bool) { lTypes, lcst := cp.CompileNode(node.Args[0], ctxt.x()) if lTypes.isOnly(values.ERROR) { - cp.P.Throw("comp/tuple/err/a", node.GetToken()) + cp.Throw("comp/tuple/err/a", node.GetToken()) } left := cp.That() rTypes, rcst := cp.CompileNode(node.Args[2], ctxt.x()) if rTypes.isOnly(values.ERROR) { - cp.P.Throw("comp/tuple/err/b", node.GetToken()) + cp.Throw("comp/tuple/err/b", node.GetToken()) } right := cp.That() leftIsError := bkEarlyReturn(DUMMY) @@ -1252,7 +1252,7 @@ func (cp *Compiler) compileForExpression(node *ast.ForExpression, ctxt Context) if node.BoundVariables == nil { if ctxt.Access != CMD && ctxt.Access != REPL { - cp.P.Throw("comp/for/bound/present", &node.Token) + cp.Throw("comp/for/bound/present", &node.Token) return altType(values.COMPILE_TIME_ERROR) } cp.Reserve(values.UNDEFINED_TYPE, nil, node.GetToken()) // If we don't have any bound variables, then this is presumptively an imperative loop and we'll need somewhere to put OK/break/error still. @@ -1261,14 +1261,14 @@ func (cp *Compiler) compileForExpression(node *ast.ForExpression, ctxt Context) hasBoundVariables = true // We set up the bound variables. Note that type checking happens *inside* the 'for' loop, not up here. if node.BoundVariables.GetToken().Type != token.ASSIGN { - cp.P.Throw("comp/for/assign/a", &node.Token) + cp.Throw("comp/for/assign/a", &node.Token) return altType(values.COMPILE_TIME_ERROR) } lhsOfBoundVariables := node.BoundVariables.(*ast.AssignmentExpression).Left rhsOfBoundVariables := node.BoundVariables.(*ast.AssignmentExpression).Right boundSig, err := cp.P.RecursivelySlurpSignature(lhsOfBoundVariables, "*default*") if err != nil { - cp.P.Throw("comp/for/bound/a", node.BoundVariables.GetToken()) + cp.Throw("comp/for/bound/a", node.BoundVariables.GetToken()) return altType(values.COMPILE_TIME_ERROR) } cp.Cm("Finding initial values of bound variables", tok) @@ -1284,7 +1284,7 @@ func (cp *Compiler) compileForExpression(node *ast.ForExpression, ctxt Context) for i, pair := range boundSig { _, exists := newEnv.GetVar(pair.VarName) if exists { - cp.P.Throw("comp/for/bound/exists", node.BoundVariables.GetToken()) + cp.Throw("comp/for/bound/exists", node.BoundVariables.GetToken()) return altType(values.COMPILE_TIME_ERROR) } cp.Reserve(values.UNDEFINED_TYPE, nil, tok) @@ -1306,14 +1306,14 @@ func (cp *Compiler) compileForExpression(node *ast.ForExpression, ctxt Context) // For the initializer we have to do something very un-DRYly like what we just did with the bound variables; TODO --- // is there any way to DRY it up that doesn't obfuscate the code? if node.Initializer.GetToken().Type != token.ASSIGN { - cp.P.Throw("comp/for/assign/b", &node.Token) + cp.Throw("comp/for/assign/b", &node.Token) return altType(values.COMPILE_TIME_ERROR) } lhsOfInitVariables := node.Initializer.(*ast.AssignmentExpression).Left rhsOfInitVariables := node.Initializer.(*ast.AssignmentExpression).Right indexSig, err := cp.P.RecursivelySlurpSignature(lhsOfInitVariables, "*default*") if err != nil { - cp.P.Throw("comp/for/bound/b", node.Initializer.GetToken()) + cp.Throw("comp/for/bound/b", node.Initializer.GetToken()) return altType(values.COMPILE_TIME_ERROR) } cp.Cm("Finding initial values of index variables", tok) @@ -1329,7 +1329,7 @@ func (cp *Compiler) compileForExpression(node *ast.ForExpression, ctxt Context) for i, pair := range indexSig { _, exists := newEnv.GetVar(pair.VarName) if exists { - cp.P.Throw("comp/for/exists/index", node.Initializer.GetToken(), pair.VarName) + cp.Throw("comp/for/exists/index", node.Initializer.GetToken(), pair.VarName) return altType(values.COMPILE_TIME_ERROR) } cp.Reserve(values.UNDEFINED_TYPE, nil, tok) @@ -1353,19 +1353,19 @@ func (cp *Compiler) compileForExpression(node *ast.ForExpression, ctxt Context) if leftId, ok := pairOfIdentifiers.Args[0].(*ast.Identifier); ok { leftName = leftId.Value } else { - cp.P.Throw("comp/for/range/a", node.GetToken()) + cp.Throw("comp/for/range/a", node.GetToken()) return altType(values.COMPILE_TIME_ERROR) } if rightId, ok := pairOfIdentifiers.Args[2].(*ast.Identifier); ok { rightName = rightId.Value } else { - cp.P.Throw("comp/for/range/b", node.GetToken()) + cp.Throw("comp/for/range/b", node.GetToken()) return altType(values.COMPILE_TIME_ERROR) } keysOnly = rightName == "_" valuesOnly = leftName == "_" if keysOnly && valuesOnly { - cp.P.Throw("comp/for/range/discard", node.GetToken()) + cp.Throw("comp/for/range/discard", node.GetToken()) return altType(values.COMPILE_TIME_ERROR) } var rangeOver ast.Node @@ -1374,7 +1374,7 @@ func (cp *Compiler) compileForExpression(node *ast.ForExpression, ctxt Context) rangeTypes, _ := cp.CompileNode(rangeOver, ctxt.x()) if len(rangeTypes.intersect(cp.Common.IsRangeable)) == 0 && !rangeTypes.Contains(values.TUPLE) { // Note that 'Contains' special-cases tuples. - cp.P.Throw("comp/for/range/types", node.GetToken()) + cp.Throw("comp/for/range/types", node.GetToken()) return altType(values.COMPILE_TIME_ERROR) } keysInt := uint32(0) @@ -1388,7 +1388,7 @@ func (cp *Compiler) compileForExpression(node *ast.ForExpression, ctxt Context) rangeKeyLoc = cp.That() _, exists := newEnv.GetVar(leftName) if exists { - cp.P.Throw("comp/for/exists/key", rangeOver.GetToken(), leftName) + cp.Throw("comp/for/exists/key", rangeOver.GetToken(), leftName) return altType(values.COMPILE_TIME_ERROR) } cp.AddVariable(newEnv, leftName, FOR_LOOP_INDEX_VARIABLE, cp.GetAlternateTypeFromTypeName("any?"), rangeOver.GetToken()) // TODO --- narrow down. @@ -1398,14 +1398,14 @@ func (cp *Compiler) compileForExpression(node *ast.ForExpression, ctxt Context) rangeValLoc = cp.That() _, exists := newEnv.GetVar(rightName) if exists { - cp.P.Throw("comp/for/exists/value", rangeOver.GetToken(), rightName) + cp.Throw("comp/for/exists/value", rangeOver.GetToken(), rightName) return altType(values.COMPILE_TIME_ERROR) } cp.AddVariable(newEnv, rightName, FOR_LOOP_INDEX_VARIABLE, cp.GetAlternateTypeFromTypeName("any?"), rangeOver.GetToken()) } } } else { - cp.P.Throw("comp/for/range/c", node.GetToken()) + cp.Throw("comp/for/range/c", node.GetToken()) return altType(values.COMPILE_TIME_ERROR) } default: @@ -1533,7 +1533,7 @@ func (cp *Compiler) resolveBreaksWithValue() { // Compile a `continue` in a `for loop`. func (cp *Compiler) emitContinue(tok *token.Token) { if len(cp.forData) == 0 { - cp.P.Throw("comp/continue", tok) + cp.Throw("comp/continue", tok) return } cp.addToForData(cp.vmContinue()) @@ -1558,7 +1558,7 @@ func (cp *Compiler) vmBreakWithValue(mLoc uint32) bkBreakWithValue { func (cp *Compiler) emitBreakWithoutValue(tok *token.Token) { if len(cp.forData) == 0 { - cp.P.Throw("comp/break/b", tok) + cp.Throw("comp/break/b", tok) return } cp.addToForData(cp.vmBreakWithoutValue()) @@ -1604,7 +1604,7 @@ func (cp *Compiler) compileLambda(env *Environment, ctxt Context, fnNode *ast.Fu v, ok := env.GetVar(k) if !ok { cp.Cm("Throwing unknown identifier error", tok) - cp.P.Throw("comp/body/known", tok, k) + cp.Throw("comp/body/known", tok, k) return } if v.access == GLOBAL_CONSTANT_PRIVATE || v.access == GLOBAL_CONSTANT_PUBLIC || v.access == LOCAL_CONSTANT { @@ -1699,7 +1699,7 @@ func (cp *Compiler) CompileGivenBlock(given ast.Node, ctxt Context) { chunks := cp.getPartsOfGiven(given, ctxt) for _, chunk := range chunks { if chunk.GetToken().Type != token.GVN_ASSIGN { - cp.P.Throw("comp/given/assign", chunk.GetToken()) + cp.Throw("comp/given/assign", chunk.GetToken()) break } assEx := chunk.(*ast.AssignmentExpression) @@ -1708,7 +1708,7 @@ func (cp *Compiler) CompileGivenBlock(given ast.Node, ctxt Context) { for _, pair := range lhsSig { _, exists := ctxt.Env.GetVar(pair.VarName) if exists { - cp.P.Throw("comp/given/exists", chunk.GetToken(), pair.VarName) + cp.Throw("comp/given/exists", chunk.GetToken(), pair.VarName) return } nameToNode[pair.VarName] = assEx @@ -1733,7 +1733,7 @@ func (cp *Compiler) CompileGivenBlock(given ast.Node, ctxt Context) { } order, cycle := dtypes.Ordering(nameGraph) if cycle != nil { - cp.P.Throw("comp/given/cycle", given.GetToken(), cycle) + cp.Throw("comp/given/cycle", given.GetToken(), cycle) } else { used := dtypes.Set[string]{} // If we have a multiple assignment, we only want to compile the rhs once. for _, v := range order { @@ -1757,7 +1757,7 @@ func (cp *Compiler) getPartsOfGiven(given ast.Node, ctxt Context) []ast.Node { rhs := cp.getPartsOfGiven(branch.Right, ctxt) result = append(result, rhs...) } else { - cp.P.Throw("comp/given/unexpected", given.GetToken()) + cp.Throw("comp/given/unexpected", given.GetToken()) } default: result = []ast.Node{given} @@ -1771,7 +1771,7 @@ func (cp *Compiler) compileOneGivenChunk(node *ast.AssignmentExpression, ctxt Co oldThis, thisExists := ctxt.Env.GetVar("this") sig, err := cp.P.RecursivelySlurpSignature(node.Left, "any?") if err != nil { - cp.P.Throw("comp/assign/lhs/b", node.Left.GetToken()) + cp.Throw("comp/assign/lhs/b", node.Left.GetToken()) return } rollbackTo := cp.GetState() @@ -1782,7 +1782,7 @@ func (cp *Compiler) compileOneGivenChunk(node *ast.AssignmentExpression, ctxt Co } resultLocation := cp.That() if types.isOnly(values.ERROR) { - cp.P.Throw("comp/assign/error", node.Left.GetToken()) + cp.Throw("comp/assign/error", node.Left.GetToken()) return } for i, pair := range sig { @@ -1792,7 +1792,7 @@ func (cp *Compiler) compileOneGivenChunk(node *ast.AssignmentExpression, ctxt Co if v.access == LOCAL_FUNCTION_THUNK && cp.Vm.Mem[v.MLoc].V == nil || v.access == LOCAL_FUNCTION_CONSTANT && cp.Vm.Mem[v.MLoc].V == nil { ctxt.Env.Data["this"] = *v } else { - cp.P.Throw("comp/given/redeclared", node.GetToken(), pair.VarName) + cp.Throw("comp/given/redeclared", node.GetToken(), pair.VarName) return } } @@ -1875,23 +1875,23 @@ func (cp *Compiler) reserveSnippetFactory(env *Environment, node *ast.SnippetLit func (cp *Compiler) compileEquals(node *ast.ComparisonExpression, ctxt Context) (AlternateType, bool) { lTypes, lcst := cp.CompileNode(node.Left, ctxt.x()) if lTypes.isOnly(values.ERROR) { - cp.P.Throw("comp/error/eq/a", node.GetToken()) + cp.Throw("comp/error/eq/a", node.GetToken()) return AltType(values.ERROR), true } leftRg := cp.That() rTypes, rcst := cp.CompileNode(node.Right, ctxt.x()) if rTypes.isOnly(values.ERROR) { - cp.P.Throw("comp/error/eq/b", node.GetToken()) + cp.Throw("comp/error/eq/b", node.GetToken()) return AltType(values.ERROR), true } rightRg := cp.That() oL := lTypes.intersect(rTypes) if oL.isOnly(values.ERROR) { - cp.P.Throw("comp/error/eq/c", node.GetToken()) + cp.Throw("comp/error/eq/c", node.GetToken()) return AltType(values.ERROR), true } if len(oL) == 0 { - cp.P.Throw("comp/eq/types", node.GetToken()) + cp.Throw("comp/eq/types", node.GetToken()) return AltType(values.ERROR), true } if len(oL) == 1 && len(lTypes) == 1 && len(rTypes) == 1 { @@ -1926,7 +1926,7 @@ func (cp *Compiler) compileLog(node *ast.LogExpression, ctxt Context) (uint32, b logStr := node.Value strList, ok := text.GetTextWithBarsAsList(logStr) if !ok { - cp.P.Throw("comp/log/close", &node.Token) + cp.Throw("comp/log/close", &node.Token) return uint32(DUMMY), false } // So at this point we have a strList consisting of things which either do or don't need parsing and compiling, @@ -1982,7 +1982,7 @@ func (cp *Compiler) compilePipe(lhsTypes AlternateType, lhsConst bool, rhs ast.N case *ast.Identifier: v, ok = env.GetVar(rhs.Value) if ok { - cp.P.Throw("comp/pipe/pipe/ident", rhs.GetToken()) + cp.Throw("comp/pipe/pipe/ident", rhs.GetToken()) return AltType(values.ERROR), true } isAttemptedFunc = true @@ -1990,7 +1990,7 @@ func (cp *Compiler) compilePipe(lhsTypes AlternateType, lhsConst bool, rhs ast.N if rhs.GetToken().Literal == "that" { // Yeah it's a stupid corner case but the stupid user has a right to it. isAttemptedFunc = false } else { - cp.P.Throw("comp/pipe/pipe/func", rhs.GetToken()) + cp.Throw("comp/pipe/pipe/func", rhs.GetToken()) return AltType(values.ERROR), true } } @@ -2044,7 +2044,7 @@ func (cp *Compiler) compileMappingOrFilter(lhsTypes AlternateType, lhsConst bool overlap := lhsTypes.intersect(cp.Common.SharedTypenameToTypeList["listlike"]) if len(overlap) == 0 { - cp.P.Throw("comp/pipe/mf/list", rhs.GetToken()) + cp.Throw("comp/pipe/mf/list", rhs.GetToken()) return AltType(values.ERROR), true } if len(overlap) < len(lhsTypes) { @@ -2069,13 +2069,13 @@ func (cp *Compiler) compileMappingOrFilter(lhsTypes AlternateType, lhsConst bool var ok bool v, ok = env.GetVar(rhs.Value) if !ok { - cp.P.Throw("comp/pipe/mf/ident", rhs.GetToken()) + cp.Throw("comp/pipe/mf/ident", rhs.GetToken()) return AltType(values.ERROR), true } isAttemptedFunc = true rhsConst = ALL_CONSTANT_ACCESS.Contains(v.access) if !v.types.Contains(values.FUNC) { - cp.P.Throw("comp/pipe/mf/func", rhs.GetToken()) + cp.Throw("comp/pipe/mf/func", rhs.GetToken()) } if !v.types.isOnly(values.FUNC) { cp.reserveError("vm/pipe/mf/func", rhs.GetToken()) @@ -2122,7 +2122,7 @@ func (cp *Compiler) compileMappingOrFilter(lhsTypes AlternateType, lhsConst bool } if isFilter { if !types.Contains(values.BOOL) { - cp.P.Throw("comp/pipe/filter/bool", rhs.GetToken()) + cp.Throw("comp/pipe/filter/bool", rhs.GetToken()) } if !types.isOnly(values.BOOL) { cp.Cm("The function we're filtering on might return something other than a boolean so we emit a check.", tok) @@ -2157,7 +2157,7 @@ func (cp *Compiler) compileSnippet(tok *token.Token, newEnv *Environment, sText bindle := values.SnippetBindle{} bits, ok := text.GetTextWithBarsAsList(sText) if !ok { - cp.P.Throw("comp/snippet/form", tok) + cp.Throw("comp/snippet/form", tok) return &bindle } bindle.CodeLoc = cp.CodeTop() @@ -2173,7 +2173,7 @@ func (cp *Compiler) compileSnippet(tok *token.Token, newEnv *Environment, sText types, _ := cp.CompileNode(node, newContext) val := cp.That() if types.Contains(values.TUPLE) { - cp.P.Throw("comp/snippet/tuple", tok) + cp.Throw("comp/snippet/tuple", tok) } bindle.ValueLocs = append(bindle.ValueLocs, val) } else { @@ -2229,7 +2229,7 @@ func (cp *Compiler) EmitTypeChecks(loc uint32, types AlternateType, env *Environ acceptedSingles := AlternateType{} lastIsTuple := sig.Len() > 0 && cp.getTypes(sig, sig.Len()-1).containsOnlyTuples() if types.isOnly(values.ERROR) { - cp.P.Throw("comp/typecheck/error", tok) + cp.Throw("comp/typecheck/error", tok) return errorCheck } if types.Contains(values.ERROR) { @@ -2242,7 +2242,7 @@ func (cp *Compiler) EmitTypeChecks(loc uint32, types AlternateType, env *Environ } checkSingleType := bkGoto(DUMMY) if len(singles) == 0 && sig.Len() == 1 { - cp.P.Throw("comp/typecheck/values/a", tok) + cp.Throw("comp/typecheck/values/a", tok) return errorCheck } if len(acceptedSingles) != len(singles) { @@ -2288,7 +2288,7 @@ func (cp *Compiler) EmitTypeChecks(loc uint32, types AlternateType, env *Environ } } if badLengths == len(lengths) { - cp.P.Throw("comp/typecheck/values/b", tok) + cp.Throw("comp/typecheck/values/b", tok) return errorCheck } @@ -2312,7 +2312,7 @@ func (cp *Compiler) EmitTypeChecks(loc uint32, types AlternateType, env *Environ sigTypes := cp.getTypes(sig, i) overlap := typesToCheck.intersect(sigTypes) if len(overlap) == 0 || overlap.isOnly(values.ERROR) { - cp.P.Throw("comp/typecheck/type", tok) + cp.Throw("comp/typecheck/type", tok) return errorCheck } if len(overlap) == len(typesToCheck) { @@ -2362,7 +2362,7 @@ func (cp *Compiler) EmitTypeChecks(loc uint32, types AlternateType, env *Environ for i := 0; i < sig.Len(); i++ { vr, ok := env.GetVar(sig.GetVarName(i)) if !ok { - cp.P.Throw("comp/typecheck/var", tok, sig.GetVarName(i)) + cp.Throw("comp/typecheck/var", tok, sig.GetVarName(i)) return bkEarlyReturn(DUMMY) } cp.Emit(vm.Asgm, vr.MLoc, errorLocation) @@ -2710,8 +2710,9 @@ func (cp *Compiler) cmR(comment string, tok *token.Token) { // The compiler keeps its errors in the CommonParserBindle like eveerything else, and accesses them through // its parser. -func (cp *Compiler) Throw(errorID string, tok token.Token, args ...any) { - cp.P.Throw(errorID, &tok, args...) +func (cp *Compiler) Throw(errorID string, tok *token.Token, args ...any) { + cp.Cm("Throwing compiler error " + errorID, tok) + cp.P.Throw(errorID, tok, args...) } func (cp *Compiler) ErrorsExist() bool { diff --git a/source/initializer/getters.go b/source/initializer/getters.go index fa739d1a..7be8df37 100644 --- a/source/initializer/getters.go +++ b/source/initializer/getters.go @@ -65,7 +65,7 @@ func (iz *initializer) getPartsOfImportOrExternalDeclaration(imp ast.Node) (stri return "", "" } -func (iz *initializer) getMatches(sigToMatch fnSigInfo, fnToTry *ast.PrsrFunction, tok *token.Token) values.AbstractType { +func (iz *initializer) getMatches(sigToMatch fnSigInfo, abSig, abRets ast.AbstractSig, fnToTry *ast.PrsrFunction, tok *token.Token) values.AbstractType { result := values.MakeAbstractType() // Check that the sigs are the right length, the return sig being optional. if sigToMatch.sig.Len() != len(fnToTry.NameSig) { @@ -78,8 +78,6 @@ func (iz *initializer) getMatches(sigToMatch fnSigInfo, fnToTry *ast.PrsrFunctio // as 'self' and take its intersection with the other things that appear in the // 'self' position. foundSelf := false - abSig := iz.p.MakeAbstractSigFromStringSig(fnToTry.NameSig) - abRets := iz.p.MakeAbstractSigFromStringSig(fnToTry.NameRets) for i := 0; i < len(sigToMatch.sig); i++ { if sigToMatch.sig.GetVarType(i).(string) == "self" { if foundSelf { diff --git a/source/initializer/gohandler.go b/source/initializer/gohandler.go index af304b19..99584a02 100644 --- a/source/initializer/gohandler.go +++ b/source/initializer/gohandler.go @@ -80,7 +80,6 @@ func (iz *initializer) newGoBucket() { // This will if necessary compile or recompile the relevant .so files, and will extract from them // the functions and converter data needed by the compiler and vm and put it into its proper place. func (iz *initializer) compileGo() { - println("Compiling Go for namespace", iz.cp.P.NamespacePath) // The purpose of putting timestamps on the .so files is not that we ever read the timestamps // from the filenames (we look either at the OS metadata of the file or at the 'gotimes' file), // but simply because you can't re-use the names of .so files in the same Go runtime and since diff --git a/source/initializer/initializer.go b/source/initializer/initializer.go index 2abfe93c..9ae5d5d4 100644 --- a/source/initializer/initializer.go +++ b/source/initializer/initializer.go @@ -154,6 +154,7 @@ func StartCompiler(scriptFilepath, sourcecode string, db *sql.DB, hubServices ma iz.cp.P.Common.IsBroken = true return result } + iz.cmI("Making function forest.") iz.MakeFunctionForests() if iz.ErrorsExist() { @@ -839,7 +840,7 @@ func (iz *initializer) createClones() { sig := ast.StringSig{ast.NameTypenamePair{"x", typeToClone}} rtnSig := ast.StringSig{ast.NameTypenamePair{"*dummy*", name}} fn := &ast.PrsrFunction{NameSig: sig, NameRets: rtnSig, Body: &ast.BuiltInExpression{Name: name}, Number: DUMMY, Compiler: iz.cp, Tok: &tok1} - iz.p.FunctionTable.Add(iz.p, name, fn) + iz.Add(name, fn) iz.fnIndex[fnSource{cloneDeclaration, i}] = fn // We get the requested builtins. @@ -990,10 +991,7 @@ func (iz *initializer) createClones() { func (iz *initializer) makeCloneFunction(fnName string, sig ast.StringSig, builtinTag string, rtnTypes compiler.AlternateType, rtnSig ast.StringSig, IsPrivate bool, pos uint32, tok *token.Token) { fn := &ast.PrsrFunction{Tok: tok, NameSig: sig, NameRets: rtnSig, Body: &ast.BuiltInExpression{*tok, builtinTag}, Compiler: iz.cp, Number: iz.addToBuiltins(sig, builtinTag, rtnTypes, IsPrivate, tok)} iz.Common.Functions[FuncSource{tok.Source, tok.Line, fnName, pos}] = fn - if fnName == settings.FUNCTION_TO_PEEK { - println("Making clone with sig", sig.String()) - } - conflictingFunction := iz.p.FunctionTable.Add(iz.p, fnName, fn) + conflictingFunction := iz.Add(fnName, fn) if conflictingFunction != nil && conflictingFunction != fn { iz.p.Throw("init/overload/c", tok, fnName, conflictingFunction.Tok) } @@ -1067,7 +1065,7 @@ func (iz *initializer) createStructNamesAndLabels() { iz.p.AllFunctionIdents.Add(name) sig := node.(*ast.AssignmentExpression).Right.(*ast.StructExpression).Sig fn := &ast.PrsrFunction{NameSig: sig, Body: &ast.BuiltInExpression{Name: name}, Number: DUMMY, Compiler: iz.cp, Tok: node.GetToken()} - iz.p.FunctionTable.Add(iz.p, name, fn) // TODO --- give them their own ast type? + iz.Add(name, fn) // TODO --- give them their own ast type? iz.fnIndex[fnSource{structDeclaration, i}] = fn // We make the labels exist, unless they already do. if typeExists { // Then the vm knows about it but we have to tell this compiler about it too. @@ -1270,9 +1268,6 @@ func (iz *initializer) findAllShareableFunctions() { // can only accept locally defined concrete types, then in principle this function might // fulfil an interface and be shared with the module that defines the interface. iz.findShareableFunctions() - if iz.ErrorsExist() { - return - } } // If a function in the module must have at least one of its parameters some type @@ -1296,7 +1291,6 @@ func (iz *initializer) findShareableFunctions() { functionToAdd := &ast.PrsrFunction{FName: functionName, NameSig: sig, Position: position, NameRets: rTypes, Body: body, Given: given, Cmd: j == commandDeclaration, Private: iz.IsPrivate(int(j), i), Number: DUMMY, Compiler: iz.cp, Tok: body.GetToken()} if iz.shareable(functionToAdd) || settings.MandatoryImportSet().Contains(tok.Source) { - // iz.cmI("Adding " + functionName + " to Common functions.") iz.Common.Functions[FuncSource{tok.Source, tok.Line, functionName, position}] = functionToAdd iz.fnIndex[fnSource{j, i}] = functionToAdd } @@ -1345,19 +1339,21 @@ func (iz *initializer) populateInterfaceTypes() { typename := nameTok.Literal typeInfo, _ := iz.getDeclaration(decINTERFACE, &nameTok, DUMMY) types := values.MakeAbstractType() - funcsToAdd := map[values.ValueType][]funcWithName{} + funcsToAdd := map[values.ValueType][]*ast.PrsrFunction{} for i, sigToMatch := range typeInfo.(interfaceInfo).sigs { typesMatched := values.MakeAbstractType() for key, fnToTry := range iz.Common.Functions { if key.FunctionName == sigToMatch.name { - matches := iz.getMatches(sigToMatch, fnToTry, &nameTok) + abSig := fnToTry.Compiler.(*compiler.Compiler).P.MakeAbstractSigFromStringSig(fnToTry.NameSig) + abRets := fnToTry.Compiler.(*compiler.Compiler).P.MakeAbstractSigFromStringSig(fnToTry.NameRets) + matches := iz.getMatches(sigToMatch, abSig, abRets, fnToTry, &nameTok) typesMatched = typesMatched.Union(matches) if !settings.MandatoryImportSet().Contains(fnToTry.Tok.Source) { for _, ty := range matches.Types { if _, ok := funcsToAdd[ty]; ok { - funcsToAdd[ty] = append(funcsToAdd[ty], funcWithName{key.FunctionName, fnToTry}) + funcsToAdd[ty] = append(funcsToAdd[ty], fnToTry) } else { - funcsToAdd[ty] = []funcWithName{{key.FunctionName, fnToTry}} + funcsToAdd[ty] = []*ast.PrsrFunction{fnToTry} } } } @@ -1377,16 +1373,12 @@ func (iz *initializer) populateInterfaceTypes() { // And we add all the implicated functions to the function table. for _, ty := range types.Types { for _, fn := range funcsToAdd[ty] { - conflictingFunction := iz.p.FunctionTable.Add(iz.p, fn.name, fn.pFunc) - if conflictingFunction != nil && conflictingFunction != fn.pFunc { - iz.p.Throw("init/overload/b", fn.pFunc.Tok, fn.name, conflictingFunction.Tok) + conflictingFunction := iz.Add(fn.FName, fn) + if conflictingFunction != nil && conflictingFunction != fn { + iz.p.Throw("init/overload/b", fn.Tok, fn.FName, conflictingFunction.Tok) } } } - } - - if settings.FUNCTION_TO_PEEK != "" { - println(iz.p.FunctionTable.Describe(iz.p, settings.FUNCTION_TO_PEEK)) } } @@ -1497,6 +1489,10 @@ func (iz *initializer) MakeFunctionTables() { dependencyIz.MakeFunctionTables() } iz.makeFunctionTable() + if settings.FUNCTION_TO_PEEK != "" { + println("In namespace", iz.p.NamespacePath) + println(iz.p.FunctionTable.Describe(iz.p, settings.FUNCTION_TO_PEEK)) + } } // Function auxillary to the above for making one function table. @@ -1526,7 +1522,7 @@ func (iz *initializer) makeFunctionTable() { Cmd: j == commandDeclaration, Private: iz.IsPrivate(int(j), i), Number: DUMMY, Compiler: iz.cp, Tok: body.GetToken()} } iz.fnIndex[fnSource{j, i}] = functionToAdd - conflictingFunction := iz.p.FunctionTable.Add(iz.p, functionName, functionToAdd) + conflictingFunction := iz.Add(functionName, functionToAdd) if conflictingFunction != nil && conflictingFunction != functionToAdd { iz.p.Throw("init/overload/a", body.GetToken(), functionName, conflictingFunction.Tok) return @@ -1544,20 +1540,12 @@ func (iz *initializer) MakeFunctionForests() { // Now we turn the function tables into a different data structure, a "function tree" with its branches labeled // with types. Following it tells us which version of an overloaded function to use. iz.MakeFunctionTrees() - if iz.ErrorsExist() { - return + if tree, ok := iz.p.FunctionForest[settings.FUNCTION_TO_PEEK]; ok && settings.FUNCTION_TO_PEEK != "" { + println("In namespace", iz.p.NamespacePath, "function tree for " + settings.FUNCTION_TO_PEEK) + println(tree.Tree.IndentString("") + "\n") } } - - -// Type for the use of the previous function. Just wraps a parser function in a struct that knows its name. -// TODO --- just put the names in the parser functions. -type funcWithName struct { - name string - pFunc *ast.PrsrFunction -} - // Function auxiliary to the above. Having made the parsers FunctionTable, each function name is associated with a // (partially) ordered list of associated functions such that a more specific type signature comes before a less // specific one. We will now re-represent this as a tree. @@ -1582,17 +1570,13 @@ func (iz *initializer) MakeFunctionTrees() { } } iz.p.FunctionForest[k] = &ast.FunctionTree{Tree: tree, RefCount: rc} - if settings.FUNCTION_TO_PEEK != "" && k == settings.FUNCTION_TO_PEEK { - println("Function tree for " + k) - println(iz.p.FunctionForest[k].Tree.IndentString("") + "\n") - } } } // Note that the sigs have already been sorted on their specificity. func (iz *initializer) addSigToTree(tree *ast.FnTreeNode, fn *ast.PrsrFunction, pos int) *ast.FnTreeNode { nameSig := fn.NameSig // TODO --- do we really need both of these? - sig := iz.cp.P.MakeAbstractSigFromStringSig(nameSig) + sig := fn.Compiler.(*compiler.Compiler).P.MakeAbstractSigFromStringSig(nameSig) if pos < len(sig) { var currentTypeName string currentAbstractType := sig[pos].VarType @@ -2379,7 +2363,9 @@ func val(T values.ValueType, V any) values.Value { // the lack of a Token parameter in its sig. For more detail, turn on the SHOW_COMPILER flag. func (iz *initializer) cmI(s string) { if settings.SHOW_INITIALIZER { - println(text.UNDERLINE + s + text.RESET + " (" + iz.cp.P.NamespacePath + ")") + if iz.cp != nil && iz.cp.P != nil { + println(text.UNDERLINE + s + text.RESET + " (" + iz.cp.P.NamespacePath + ")") + } } } @@ -2392,3 +2378,42 @@ func (iz *initializer) Throw(errorID string, tok *token.Token, args ...any) { func (iz *initializer) ErrorsExist() bool { return iz.p.ErrorsExist() } + +// Methods for manipulating the function table. + +func (iz *initializer) Add(functionName string, f *ast.PrsrFunction) *ast.PrsrFunction { + if functions, ok := iz.cp.P.FunctionTable[functionName]; ok { + functions, conflictingFunction := iz.AddInOrder(functions, f) + iz.cp.P.FunctionTable[functionName] = functions + return conflictingFunction + } + iz.cp.P.FunctionTable[functionName] = []*ast.PrsrFunction{f} + return nil +} + +func (iz *initializer) AddInOrder(S []*ast.PrsrFunction, f *ast.PrsrFunction) ([]*ast.PrsrFunction, *ast.PrsrFunction) { + fSig := f.Compiler.(*compiler.Compiler).P.MakeAbstractSigFromStringSig(f.NameSig) + for i := 0; i < len(S); i++ { + gSig := S[i].Compiler.(*compiler.Compiler).P.MakeAbstractSigFromStringSig(S[i].NameSig) + yes, ok := parser.IsMoreSpecific(fSig, gSig) + if !ok { + return S, S[i] + } + if yes { + S = insert(S, f, i) + return S, nil + } + } + S = append(S, f) + return S, nil +} + + +func insert(a []*ast.PrsrFunction, value *ast.PrsrFunction, index int) []*ast.PrsrFunction { + if len(a) == index { // nil or empty slice or after last element + return append(a, value) + } + a = append(a[:index+1], a[index:]...) // index < len(a) + a[index] = value + return a +} diff --git a/source/parser/function_table.go b/source/parser/function_table.go index 1b7d98b8..006349ea 100644 --- a/source/parser/function_table.go +++ b/source/parser/function_table.go @@ -6,21 +6,11 @@ import ( type FunctionTable map[string][]*ast.PrsrFunction -func (ft FunctionTable) Add(p *Parser, functionName string, f *ast.PrsrFunction) *ast.PrsrFunction { - if functions, ok := ft[functionName]; ok { - functions, conflictingFunction := p.AddInOrder(functions, f) - ft[functionName] = functions - return conflictingFunction - } - ft[functionName] = []*ast.PrsrFunction{f} - return nil -} - func (ft FunctionTable) Describe(p *Parser, functionName string) string { result := "Function table for " + functionName + "\n\n" if functions, ok := ft[functionName]; ok { for _, f := range functions { - result = result + f.NameSig.String() + "\n:\n" + f.Body.String() + "\n\n" + result = result + f.NameSig.String() + " : " + f.Body.String() + "\n\n" } return result } else { diff --git a/source/parser/parser.go b/source/parser/parser.go index b35536aa..1c4ac6da 100644 --- a/source/parser/parser.go +++ b/source/parser/parser.go @@ -50,7 +50,7 @@ type Parser struct { nativeInfixes dtypes.Set[token.TokenType] lazyInfixes dtypes.Set[token.TokenType] - // Used for multiple dispatch. + // Used for multiple dispatch. TODO --- neither of these should be in the parser. // While this is mostly just used by the initializer to construct the function trees (below), it is also used // to serialize the API and so may be needed at runtime. diff --git a/source/parser/types.go b/source/parser/types.go index bcefe091..24aa9053 100644 --- a/source/parser/types.go +++ b/source/parser/types.go @@ -61,7 +61,7 @@ var ClonableTypes = map[string]values.ValueType{"float": values.FLOAT, "int": va var AbstractTypesOtherThanSingle = []string{"struct", "enum"} -func (p *Parser) IsMoreSpecific(sigA, sigB ast.AbstractSig) (result bool, ok bool) { +func IsMoreSpecific(sigA, sigB ast.AbstractSig) (result bool, ok bool) { if len(sigB) == 0 { result = true ok = true @@ -157,28 +157,5 @@ func UnnullType(maybeNulled string) string { } } -func insert(a []*ast.PrsrFunction, value *ast.PrsrFunction, index int) []*ast.PrsrFunction { - if len(a) == index { // nil or empty slice or after last element - return append(a, value) - } - a = append(a[:index+1], a[index:]...) // index < len(a) - a[index] = value - return a -} -func (p *Parser) AddInOrder(S []*ast.PrsrFunction, f *ast.PrsrFunction) ([]*ast.PrsrFunction, *ast.PrsrFunction) { - fSig := p.MakeAbstractSigFromStringSig(f.NameSig) - for i := 0; i < len(S); i++ { - gSig := p.MakeAbstractSigFromStringSig(S[i].NameSig) - yes, ok := p.IsMoreSpecific(fSig, gSig) - if !ok { - return S, S[i] - } - if yes { - S = insert(S, f, i) - return S, nil - } - } - S = append(S, f) - return S, nil -} + diff --git a/source/settings/settings.go b/source/settings/settings.go index 2978ffdd..64dd04d2 100644 --- a/source/settings/settings.go +++ b/source/settings/settings.go @@ -21,7 +21,7 @@ func MandatoryImportSet() dtypes.Set[string] { return dtypes.MakeFromSlice(MandatoryImports) } -var ThingsToIgnore = (dtypes.MakeFromSlice(MandatoryImports)).Add("rsc-pf/hub.pf").Add("Builtin constant").Add("rsc/worldlite.pf") +var ThingsToIgnore = (dtypes.MakeFromSlice(MandatoryImports)).Add("rsc-pf/hub.pf").Add("Builtin constant").Add("rsc-pf/worldlite.pf") // This is replicated in the hub and any changes made here must be reflected there. TODO --- don't. var StandardLibraries = dtypes.MakeFromSlice([]string{"path/filepath", "fmt", "math", "path", "regexp", "strings", "time", "unicode"}) @@ -42,7 +42,7 @@ const ( SHOW_RUNTIME = false // Note that this will show the hub's runtime too at present 'cos it can't tell the difference. TODO. SHOW_RUNTIME_VALUES = false // Shows the contents of memory locations on the rhs of anything (i.e. not the dest). SHOW_XCALLS = false - SHOW_GOLANG = true + SHOW_GOLANG = false SHOW_API_SERIALIZATION = false SHOW_EXTERNAL_STUBS = false SHOW_TESTS = true // Says whether the tests should say what is being tested, useful if one of them crashes and we don't know which.