Transpiled version (31146L) is out of date.
/* e.g. overlay <- ScreenOverlay bounds <- rightScreenBounds overlay bounds bounds overlay show Can separate commands with ";" also. For how to define functions in a script see #1033988. Note: LeftArrowScriptAutoCompleter uses a lot of this class's internals */ sclass GazelleV_LeftArrowScriptParser > SimpleLeftToRightParser { replace Toolbox with GazelleV_LeftArrowScript. delegate Script, Evaluable, FunctionDef, FixedVarBase to Toolbox. replace const with _const. ClassNameResolver classNameResolver; new L functionContainers; settable ILASClassLoader lasClassLoader; settable S classDefPrefix; settable bool optimize = true; settable bool useFixedVarContexts = false; // doesn't completely work yet LASScope scope; new LinkedHashMap<S, LASValueDescriptor> knownVars; new L<FixedVarBase> varAccessesToFix; Set<S> closerTokens = litset(";", "}", ")"); BuildingScript currentReturnableScript; BuildingScript currentLoop; bool inParens; int idCounter; new Map<S, LASClassDef> classDefs; // record which vars are known at current parse location event knownVarsSnapshot(Map<S, LASValueDescriptor> knownVars); replace print with if (GazelleV_LeftArrowScriptParser.this.scaffoldingEnabled()) print. replace printVars with if (GazelleV_LeftArrowScriptParser.this.scaffoldingEnabled()) printVars. // object can be a class srecord MethodOnObject(O object, S method) {} srecord EvaluableWrapper(Evaluable expr) {} class BuildingScript { int id = ++idCounter; settable bool returnable; settable bool isLoopBody; BuildingScript returnableParent, loopParent; settable LASScope scope; new Script script; new L<Evaluable> steps; Map<S, FunctionDef> functionDefs = new Map; *(bool *returnable) { this(); } *(bool *returnable, bool *isLoopBody) { this(); } *() { scope = currentScope(); } void add(Evaluable step) { if (step != null) steps.add(step); } Evaluable get() { script.scope = scope; // if the last command is a return from THIS script, // convert into a simple expression var lastStep = last(steps); if (lastStep cast Toolbox.ReturnFromScript) if (lastStep.script == script) replaceLast(steps, lastStep.value); // if the script is only step, is not returnable // and defines no functions, replace it with its only step if (!returnable && l(steps) == 1 && empty(functionDefs)) ret first(steps); // make and return actual script if (nempty(functionDefs)) script.functionDefs = functionDefs; script.steps = toTypedArray(Evaluable.class, steps); ret script; } S toStringLong() { ret pnlToLines(steps); } toString { ret formatRecordVars BuildingScript(+id, +returnable , +returnableParent, +script); } } // end of BuildingScript Script parse(S text) { setText(text); init(); ret parse(); } Script parse() { Script script = parseReturnableScript(); for (varAccess : varAccessesToFix) varAccess.resolve(); if (optimize) script = script.optimizeScript(); ret script; } Script parseReturnableScript() { ret (Script) parseScript(new BuildingScript().returnable(true)); } // if returnable is true, it's always a Script Evaluable parseScript(BuildingScript script) { ret linkToSrc(-> { script.returnableParent = currentReturnableScript; script.loopParent = currentLoop; if (script.returnable) currentReturnableScript = script; if (script.isLoopBody) currentLoop = script; ret parseBuildingScript(script); }); } Evaluable parseBuildingScript(BuildingScript script) { try { parseScript_2(script); var builtScript = script!; currentReturnableScript = script.returnableParent; currentLoop = script.loopParent; ret builtScript; } catch e { print("Parsed so far:\n" + script); throw rethrowAndAppendToMessage(e, squareBracketed(str(lineAndColumn(-1)))); } } void parseScript_2(BuildingScript script) { temp tempRestoreMap(knownVars); new AssureAdvance assure; while (assure!) { // for auto-completer knownVarsSnapshot(knownVars); print("parseScript_2: Next token is " + quote(token())); if (is(";")) continue with next(); if (isOneOf("}", ")")) break; Evaluable instruction = linkToSrc(-> parseInstruction(script)); if (instruction != null) script.add(instruction); } print("parseScript_2 done"); knownVarsSnapshot(knownVars); } Evaluable parseInstruction(BuildingScript script) { if (is("def")) { parseFunctionDefinition(currentReturnableScript.functionDefs); null; } if (is("param")) { consume(); S var = assertIdentifier(tpp()); new LASValueDescriptor valueDescriptor; if (is(":")) { var type = parseColonType(); valueDescriptor = LASValueDescriptor.nonExactCanBeNull(type); } knownVars.put(var, valueDescriptor); null; } if (is("throw")) { consume(); ret new Toolbox.Throw(parseExpr()); } if (is("try")) { consume(); Evaluable body = parseCurlyBlock(new BuildingScript); consume("catch"); S var = consumeIdentifier(); temp tempAddKnownVars(var); Evaluable catchBlock = parseCurlyBlock(new BuildingScript); ret new Toolbox.TryCatch(body, var, catchBlock); } if (isOneOf("return", "ret")) { consume(); Evaluable expr; if (atCmdEnd()) expr = const(null); else expr = parseAssignmentOrExpr(); ret new Toolbox.ReturnFromScript(currentReturnableScript.script, expr); } if (is("continue")) { consume(); assertCmdEnd(); if (currentLoop == null) fail("continue outside of loop"); ret new Toolbox.Continue(currentLoop.script); } if (is("temp")) { consume(); Evaluable tempExpr = parseExpr(); print(+tempExpr); Evaluable body = parseScript(new BuildingScript); print(+body); ret new Toolbox.TempBlock(tempExpr, body); } if (is("class")) ret new Toolbox.ClassDef(new ResolvableLASClass(lasClassLoader, parseClassDef())); ret parseAssignmentOrExpr(); } Evaluable parseAssignmentOrExpr() { try object parseAssignmentOpt(); ret parseExpr(); } Evaluable parseAssignmentOpt() { S t = token(); if (isIdentifier(t) && eq(token(1), "<") && eq(token(2), "-")) { print("Found assignment"); next(3); Evaluable rhs = parseExpr(); assertNotNull("Expression expected", rhs); bool newVar = !knownVars.containsKey(t); printVars(+newVar, +t, +knownVars); knownVars.put(t, new LASValueDescriptor); ret newVar ? new Toolbox.VarDeclaration(t, null, rhs) : new Toolbox.Assignment(t, rhs); } null; } Evaluable parseOptionalInnerExpression() { printVars parseOptionalInnerExpression(+token()); if (atCmdEnd() || isOneOf("{", ",")) null; ret parseInnerExpr(); } Evaluable const(O o) { ret new Toolbox.Const(o); } Evaluable parseInnerExpr() { ret parseExpr(true); } scaffolded Evaluable parseExpr(bool inner default false) { Evaluable e = linkToSrc(-> inner ? parseExpr_impl(true) : parseExprPlusOptionalComma()); print("parseExpr done:\n" + Toolbox.indentedScriptStruct(e)); ret e; } Evaluable parseExprPlusOptionalComma() { Evaluable expr = parseExpr_impl(false); //printVars("parseExprPlusOptionalComma", t := t()); while (consumeOpt(",")) { expr = parseCall_noCmdEndCheck(expr); //printVars("parseExprPlusOptionalComma", t2 := t()); } ret expr; } Evaluable parseExpr_impl(bool inner) { if (atEnd()) null; S t = token(); printVars parseExpr(token := t); if (is(";")) null; // empty command if (is("{")) ret parseCurlyBlock(new BuildingScript); // int or double literal if (is("-") && empty(nextSpace()) && startsWithDigit(token(1)) || startsWithDigit(t)) { var e = parseNumberLiteral(); ret inner ? e : parseCall(e); } if (isQuoted(t)) { consume(); var e = const(unquote(t)); ret inner ? e : parseCall(e); } if (startsWith(t, '\'')) { consume(); var e = const(first(unquote(t))); ret inner ? e : parseCall(e); } if (isIdentifier(t)) { if (is("while")) ret parseWhileLoop(); if (is("for")) ret parseForEach(); if (is("if")) ret parseIfStatement(); if (is("repeat")) ret parseRepeatStatement(); if (is("outer")) { consume(); var a = parseAssignmentOpt(); if (!a instanceof Toolbox.Assignment) fail("Assignment expected"); cast a to Toolbox.Assignment; ret new Toolbox.AssignmentToOuterVar(a.var, a.expression); } consume(); print("Consumed identifier " + t + ", next token: " + token() + ", inner: " + inner); ret parseExprStartingWithIdentifier(t, inner); } // nested expression if (eq(t, "(")) { bool inParensOld = inParens; inParens = true; consume(); //print("Consumed opening parens (level " + parenLevels + ")"); var e = parseExpr(); //print("Consuming closing parens for expr: " + e + " (closing paren level " + parenLevels + ")"); consume(")"); inParens = inParensOld; ret inner ? e : parseCall(e); } if (isOneOf("&", "|") && empty(nextSpace()) && is(1, token())) { ret parseBinaryOperator(); } fail("Identifier, literal, operator or opening parentheses expected (got: " + quote(t)); } Evaluable parseNumberLiteral() { S t = consumeMultiTokenLiteral(); if (swic(t, "0x")) ret const(parseHexInt(dropFirst(t, 2))); if (swic(t, "0b")) ret const(intFromBinary(dropFirst(t, 2))); if (isInteger(t)) ret const(parseInt(t)); if (endsWith(t, "f")) ret const(parseFloat(t)); if (endsWith(t, "L")) ret const(parseLong(t)); ret const(parseDouble(t)); } Evaluable parseBinaryOperator() { bool and = is("&"); next(2); Evaluable a = parseInnerExpr(); Evaluable b = parseInnerExpr(); ret and ? new Toolbox.BoolAnd(a, b) : new Toolbox.BoolOr(a, b); } bool qualifiedNameContinues() { ret empty(prevSpace()) && eq(token(), ".") && empty(nextSpace()) && isIdentifier(token(1)); } // t is last consumed token (the identifier the expression starts with) Evaluable parseExprStartingWithIdentifier(S t, bool inner) { if (eq(t, "true")) ret const(true); if (eq(t, "false")) ret const(false); if (eq(t, "null")) ret const(null); if (eq(t, "new")) { S className = assertIdentifier(tpp()); parseTypeArguments(null); // script-defined class? LASClassDef cd = classDefs.get(className); if (cd != null) ret new Toolbox.NewObject_LASClass(new ResolvableLASClass(lasClassLoader, cd)); // class in variable? please include function newObject. var type = knownVars.get(className); if (type != null) ret new Toolbox.NewObject_UnknownClass(new Toolbox.GetVar(className), parseArguments()); // external class O o = findExternalObject(className); if (o cast Class) { Class c = o; if (c == L.class) c = ArrayList.class; else if (c == Map.class) c = HashMap.class; else if (c == Set.class) c = HashSet.class; ret new Toolbox.NewObject(c, parseArguments()); } throw new ClassNotFound(className); } // First search variable in local scope if it's a fixed vars scope if (scope != null && scope.useFixedVars) { var type = scope.declaredVars.get(t); if (type != null) { var e = new Toolbox.GetFixedVar(scope, t); e.scope(scope); e.returnType(type); varAccessesToFix.add(e); ret inner ? e : parseCall(e); } } // Now search in outer scopes (should rework this) var type = knownVars.get(t); if (type != null) { var e = new Toolbox.GetVar(t).returnType(type); print("Found var acccess: " + e + ", " + (!inner ? "Checking for call" : "Returning expression")); ret inner ? e : parseCall(e); } if (!inner) { var fdef = lookupFunction(t); if (fdef != null) ret new Toolbox.CallFunction(fdef, parseArguments()); } if (eq(t, "_context")) ret new Toolbox.GetVarContext; O o = findExternalObject(t); if (o == null) { //unconsume(); throw new UnknownObject(t); } else if (o cast EvaluableWrapper) { ret inner ? o.expr : parseCall(o.expr); } else if (inner) ret const(o); else if (o cast Class) { ret parseExprStartingWithClass(o); } else if (o cast MethodOnObject) { if (inner) fail("Can't call methods in arguments"); ret new Toolbox.CallMethod(const(o.object), o.method, parseArguments()); } else ret parseCall(const(o)); } Evaluable parseExprStartingWithClass(Class c) { if (atCmdEnd()) ret const(c); // new without new if (is("(")) ret new Toolbox.NewObject(c, parseArguments()); /* old object creation syntax (e.g. Pair new a b) if (is("new")) { next(); ret new Toolbox.NewObject(c, parseArguments()); } else*/ // check if it's a lambda definition first (with ->) try object parseLambdaOpt(c); if (isIdentifier()) { S name = tpp(); // We have now parsed a class (c) plus an as yet unknown identifier (name) right next to it // look for a static method call if (hasStaticMethodNamed(c, name)) ret new Toolbox.CallMethod(const(c), name, parseArguments()); // if the class is an interface, it's a lambda method reference or a lambda if (isInterface(c)) ret parseLambdaMethodRef(c, name); // look for field second var field = getField(c, name); if (field != null) { assertCmdEnd(); if (!isStaticField(field)) fail(field + " is not a static field"); ret new Toolbox.GetStaticField(field); } fail(name + " not found in " + c + " (looked for method or field)"); } else fail("Method name expected: " + token()); } // parse lambda, e.g. IF1 a -> plus a a // returns null if it's not a lambda Evaluable parseLambdaOpt(Class c) { int nArgs = 0; while (isIdentifier(token(nArgs))) nArgs++; if (!(is(nArgs, "-") && is(nArgs+1, ">"))) null; // not a lambda // read parameter names and add to known variables S[] argNames = consumeArray(nArgs); temp tempAddKnownVars(argNames); skip(2); // skip the arrow Evaluable body; // if curly brackets: parse lambda body as returnable script // TODO: avoid script overhead if there are no return calls inside if (is("{")) body = parseReturnableScript(); else // no curly brackets => just an expression body = parseExpr(); // return lambda var lambda = new Toolbox.LambdaDef(c, argNames, body); print("parseLambdaOpt done:\n" + Toolbox.indentedScriptStruct(lambda)); ret lambda; } // method ref, e.g. "IF1 l" meaning "l1 l" // also, constructor ref, e.g. "IF1 Pair" meaning (x -> new Pair(x)) // // c must be a single method interface Evaluable parseLambdaMethodRef(Class c, S name) { var fdef = lookupFunction(name); if (fdef != null) { Evaluable[] curriedArguments = parseArguments(); ret new Toolbox.CurriedScriptFunctionLambda(c, fdef, curriedArguments); } O function = findExternalObject(name); if (function == null) throw new UnknownObject(name); if (function cast MethodOnObject) { O target = function.object; S targetMethod = function.method; Evaluable[] curriedArguments = parseArguments(); ret new Toolbox.CurriedMethodLambda(c, target, targetMethod, curriedArguments); } else if (function cast Class) { Class c2 = function; // No currying here yet assertCmdEnd(); var ctors = constructorsWithNumberOfArguments(c2, 1); if (empty(ctors)) fail("No single argument constructor found in " + c2); ret new Toolbox.CurriedConstructorLambda(c, toArray Constructor(ctors), null); } else fail(function + " is not an instantiable class or callable method"); } FunctionDef lookupFunction(S name) { var script = currentReturnableScript; while (script != null) { var f = script.functionDefs.get(name); printVars("lookupFunction", +script, +name, +f); if (f != null) ret f; script = script.returnableParent; } null; } Evaluable[] parseArguments() { ret toArrayOrNull(Evaluable.class, parseArgumentsAsList()); } L<Evaluable> parseArgumentsAsList() { //ret collectWhileNotNull(-> parseOptionalInnerExpression()); new L<Evaluable> l; try { while (true) { Evaluable a = parseOptionalInnerExpression(); if (a == null) break; l.add(a); } ret l; } on fail { print("Arguments parsed so far: " + l); } } S consumeMultiTokenLiteral() { ret consumeUntilSpaceOr(-> atCmdEnd() || is(",")); } bool atCmdEnd() { ret !inParens && atEndOrLineBreak() || closerTokens.contains(token()); } void assertCmdEnd() { if (!atCmdEnd()) fail("Expected end of command, token is: " + quote(token())); } // After we just parsed an expression, see if there is something // to the right of it. // Currently that can be // -a method call // -a field access // -a field assignment (e.g.: myPair a <- 1) Evaluable parseCall(Evaluable target) { // normally, do a check for end of line if (atCmdEnd()) ret target; ret parseCall_noCmdEndCheck(target); } Evaluable parseCall_noCmdEndCheck(Evaluable target) { // in every case, we expect an identifier first if (!isIdentifier()) ret target; var start = ptr(); S name = tpp(); // the identifier // check for field assignment if (eq(token(), "<") && eq(token(1), "-")) { next(2); Evaluable rhs = parseExpr(); ret new Toolbox.SetField(target, name, rhs); } var args = parseArguments(); if (nempty(args)) ret new Toolbox.CallMethod(target, name, args); else ret linkToSrc(start, new Toolbox.CallMethodOrGetField(target, name)); } // add link to source code to parsed object if it supports it // and doesn't have a source code link already <A> A linkToSrc(TokPtr start, A a) { if (a cast IHasTokenRangeWithSrc /*&& a.tokenRangeWithSrc() == null*/) a.setTokenRangeWithSrc(TokenRangeWithSrc(start, ptr().plus(-1))); ret a; } // lambda version of linkToSrc <A> A linkToSrc(IF0<A> a) { var start = ptr(); ret linkToSrc(start, a!); } // can return MethodOnObject // Note: Assumes we just parsed the name // TODO: rename this part of the method swappable O findExternalObject(S name) { //try object findClassThroughDefaultClassFinder(name); //try object findClassInStandardImports(name); try object parsePrimitiveType(name); if (qualifiedNameContinues()) { int idx = idx()-2; do next(2); while (qualifiedNameContinues()); S fqn = joinSubList(tok, idx, idx()-1); ret classForName(fqn); } S fullName = globalClassNames().get(name); if (fullName != null) ret classForName(fullName); fOr (container : functionContainers) { if (hasMethodNamed(container, name)) ret new MethodOnObject(container, name); var field = getField(container, name); if (field != null && isStaticField(field)) ret new EvaluableWrapper(new Toolbox.GetStaticField(field)); } null; } selfType allowTheWorld() { ret allowTheWorld(mc()); } // first containers within argument list have priority // last calls to allowTheWorld/first arguments passed have priority selfType allowTheWorld(O... functionContainers) { fOr (O o : reversed(functionContainers)) if (!contains(this.functionContainers, o)) { this.functionContainers.add(0, o); globalClassNames_cache = null; // recalculate } this; } void printFunctionDefs(Script script) { print(values(script.functionDefs)); } AutoCloseable tempAddKnownVars(S... vars) { ret tempAddKnownVars(asList(vars)); } AutoCloseable tempAddKnownVars(Iterable<S> vars) { var newVars = mapWithSingleValue(vars, new LASValueDescriptor); if (scope != null) for (name, type : newVars) scope.addDeclaredVar(name, type); ret tempMapPutAll(knownVars, newVars); } Toolbox.FunctionDef parseFunctionDefinition(Map<S, FunctionDef> functionDefsToAddTo) { consume("def"); S functionName = assertIdentifier(tpp()); print("parseFunctionDefinition " + functionName); new LS args; while (isIdentifier()) args.add(tpp()); var scope = newScope(); scope.useFixedVars(useFixedVarContexts); temp tempScope(scope); temp tempAddKnownVars(args); print("Parsing function body"); var functionBody = parseReturnableCurlyBlock(); print("Defined function " + functionName + ", adding to " + functionDefsToAddTo); var fd = new Toolbox.FunctionDef(functionName, args, functionBody); fd.scope(scope); functionDefsToAddTo?.put(functionName, fd); ret fd; } LASScope newScope() { ret new LASScope(scope); } LASScope currentScope() { ret scope; } // enter the scope temporarily AutoCloseable tempScope(LASScope scope) { var oldScope = currentScope(); this.scope = scope; ret -> { scope.resolve(); this.scope = oldScope; }; } Script parseReturnableCurlyBlock() { ret (Script) parseCurlyBlock(new BuildingScript().returnable(true)); } Evaluable parseCurlyBlock(BuildingScript script) { //print(+knownVars); consume("{"); bool inParensOld = inParens; inParens = false; var body = parseScript(script); consume("}"); inParens = inParensOld; ret body; } Evaluable parseWhileLoop() { consume("while"); var condition = parseExpr(); var body = parseCurlyBlock(new BuildingScript().isLoopBody(true)); ret new Toolbox.While(condition, body); } Evaluable parseForEach() { ret new ParseForEach()!; } class ParseForEach { Evaluable collection, body; IF0<Evaluable> finish; new Set<S> vars; S addVar(S var) { ret addAndReturn(vars, var); } S consumeVar() { ret addVar(consumeIdentifier()); } void parseBody { temp tempAddKnownVars(vars); body = parseCurlyBlock(new BuildingScript().isLoopBody(true)); } Evaluable get() { consume("for"); // for i to n { ... } if (is(1, "to")) { S var = consumeVar(); consume("to"); Evaluable endValue = parseExpr(); parseBody(); ret new Toolbox.ForIntTo(endValue, var, body); } int iIn = relativeIndexOf("in"); if (iIn < 0) fail("for without in"); print(+iIn); if (iIn == 1) { // just a variable S var = consumeVar(); finish = -> new Toolbox.ForEach(collection, var, body); } else if (iIn == 2) { // for iterator (mapI) if (consumeOpt("iterator")) { S var = consumeVar(); finish = -> new Toolbox.ForIterator(collection, var, body); } else if (consumeOpt("nested")) { S var = consumeVar(); finish = -> new Toolbox.ForNested(collection, var, body); } else fail("Unknown pattern for 'for' loop"); } else if (iIn == 3) { if (isOneOf("pair", "Pair")) { // "pair a b" or "Pair a b" consume(); S varA = consumeVar(); S varB = consumeVar(); printVars(+varA, +varB); finish = -> new Toolbox.ForPairs(collection, body, varA, varB); } else { // "a, b" S varA = consumeVar(); consume(","); S varB = consumeVar(); finish = -> new Toolbox.ForKeyValue(collection, body, varA, varB); } } else if (iIn == 4) { consume("index"); S varIndex = consumeVar(); consume(","); S varElement = consumeVar(); finish = -> new Toolbox.ForIndex(collection, body, varIndex, varElement); } else fail("Unknown pattern for 'for' loop"); consume("in"); collection = parseExpr(); print(+collection); parseBody(); ret finish!; } } Evaluable parseIfStatement() { consume("if"); Evaluable condition, body, elseBranch = null; { temp tempAdd(closerTokens, "then"); condition = parseExpr(); } if (consumeOpt("then")) { temp tempAdd(closerTokens, "else"); body = parseExpr(); if (consumeOpt("else")) elseBranch = parseExpr(); } else { body = parseCurlyBlock(new BuildingScript); if (consumeOpt("else")) { if (is("if")) elseBranch = parseIfStatement(); else elseBranch = parseCurlyBlock(new BuildingScript); } } ret new Toolbox.IfThen(condition, body, elseBranch); } Evaluable parseRepeatStatement() { consume("repeat"); var n = parseExpr(); var body = parseCurlyBlock(new BuildingScript); ret new Toolbox.RepeatN(n, body); } // declare an external variable with optional type info void addVar(S var, LASValueDescriptor type default new) { knownVars.put(var, type); } void addVar(S var, Class type, bool canBeNull) { addVar(var, new LASValueDescriptor.NonExact(type, canBeNull)); } // short name to full name // TODO: sort by priority if classes appear twice simplyCached SS globalClassNames() { var packages = mapToTreeSet(importedPackages(), pkg -> pkg + "."); new SS out; // add function containers themselves (if they're classes) for (fc : functionContainers) if (fc cast Class) { if (isAnonymousClass(fc)) continue; out.put(shortClassName(fc), className(fc)); } // add inner classes of function containers var classContainers = classContainerPrefixes(); TreeSet<S> classContainerSet = asTreeSet(classContainers); out.put("List", "java.util.List"); for (className : classNameResolver().allFullyQualifiedClassNames()) { if (isAnonymousClassName(className)) continue; if (!contains(className, '$')) { S pkg = longestPrefixInTreeSet(className, packages); if (pkg != null) { S shortName = dropPrefix(pkg, className); if (!shortName.contains(".") && !out.containsKey(shortName)) out.put(shortName, className); } } S container = longestPrefixInTreeSet(className, classContainerSet); if (container != null) { S shortName = dropPrefix(container, className); S existing = out.get(shortName); if (existing != null) { int priority = indexOf(classContainers, container); S oldContainer = longestPrefixInTreeSet(existing, classContainerSet); int oldPriority = indexOf(classContainers, oldContainer); printVars(+className, +shortName, +container, +priority, +existing, +oldPriority); if (priority > oldPriority) continue; } out.put(shortName, className); } } for (key, val : javaxClassShortcuts()) { S fullName = out.get(val); if (fullName != null) out.put(key, fullName); } ret out; } swappable Cl<S> importedPackages() { ret itemPlus("java.lang", standardImports_fullyImportedPackages()); } void addClassAlias(S alias, S longName) { S fullName = globalClassNames().get(longName); if (fullName != null) globalClassNames().put(alias, fullName); } LS classContainerPrefixes() { ret map(functionContainers, fc -> className(fc) + "$"); } // typed exceptions (unusual, I know!) srecord noeq UnknownObject(S name) > RuntimeException { public S getMessage() { ret "Unknown object: " + name; } } sclass ClassNotFound > UnknownObject { *(S className) { super(className); } public S getMessage() { ret "Class not found: " + name; } } LASClassDef parseClassDef() { consume("class"); new LASClassDef classDef; classDef.verbose(scaffoldingEnabled()); if (nempty(classDefPrefix)) classDef.classDefPrefix(classDefPrefix); S name = consumeIdentifier(); classDef.userGivenName(name); consume("{"); // parse class body while (!is("}")) { if (is(";")) continue with next(); // parse method declaration if (is("def")) { temp tempAddKnownVars("this"); Toolbox.FunctionDef fd = parseFunctionDefinition(null); printVars(knownVarsAfterFunctionDef := knownVars); classDef.methods.add(fd); continue; } // parse field declaration new LASClassDef.FieldDef fd; fd.name(consumeIdentifier()); var type = parseColonType(); fd.type(type); classDef.fields.add(fd); } consume("}"); classDefs.put(name, classDef); ret classDef; } Type parseColonType() { consume(":"); S typeName = consumeIdentifier(); O type = findExternalObject(typeName); if (!type instanceof Class) fail("Class not found: " + typeName); cast type to Type; ret parseTypeArguments(type); } Type parseTypeArguments(Type type) { // type arguments if (is("<") && isIdentifier(token(1))) { next(); O arg = findExternalObject(consume()); consume(">"); // only one parameter supported so far if (!arg instanceof Class) fail("Class not found: " + arg); if (type != null) type = new ParameterizedTypeImpl(null, type, (Class) arg); } ret type; } swappable Class classForName(S name) ctex { ret Class.forName(name); } // also copies the globalClassNames_cache which otherwise takes // a few ms to calculate void copyFunctionContainersFrom(GazelleV_LeftArrowScriptParser parser) { functionContainers = cloneList(parser.functionContainers); globalClassNames_cache = parser.globalClassNames(); } ClassNameResolver classNameResolver() { if (classNameResolver == null) classNameResolver = new ClassNameResolver().byteCodePath(assertNotNull(getBytecodePathForClass(this))).init(); ret classNameResolver; } selfType classNameResolver(ClassNameResolver classNameResolver) { this.classNameResolver = classNameResolver; this; } } // end of GazelleV_LeftArrowScriptParser
download show line numbers debug dex old transpilations
Travelled to 4 computer(s): bhatertpkbcr, ekrmjmnbrukm, mowyntqkapby, mqqgnosmbjvj
No comments. add comment
Snippet ID: | #1033976 |
Snippet name: | GazelleV_LeftArrowScriptParser |
Eternal ID of this version: | #1033976/398 |
Text MD5: | 9a17df42cea2e7928bf7c0fd2d3673c4 |
Author: | stefan |
Category: | javax |
Type: | JavaX fragment (include) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2022-05-14 02:57:07 |
Source code size: | 32821 bytes / 1096 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 823 / 3174 |
Version history: | 397 change(s) |
Referenced in: | [show references] |