C# Class kOS.Safe.Compilation.KS.Compiler

Datei anzeigen Open project: KSP-KOS/KOS Class Usage Examples

Public Methods

Method Description
Compile ( int startLineNum, ParseTree tree, Context context, CompilerOptions options ) : CodePart
VisitDirective ( ParseNode node ) : void
VisitLazyGlobalDirective ( ParseNode node ) : void

Private Methods

Method Description
AddFunctionJumpVars ( ParseNode node ) : void

Add all the variables at this local scope for holding the jump addresses to go to for the given function names defined in this scope. Pass a NULL to mean global scope.

AddOpcode ( Opcode opcode ) : Opcode
AddOpcode ( Opcode opcode, string destinationLabel ) : Opcode
AddToBreakList ( Opcode opcode ) : void
BeginScope ( ParseNode node ) : void

Insert the Opcode to start a new lexical scope, handling the parent id mapping. Call upon every open brace "{"

BuildFunctionDelegate ( bool isDirect, string directName = "" ) : void

When a function identifier or suffix ends in '@' where parentheses could have gone, then its not really being called like a function. Instead it's being asked to generate a delegate of itself to be put atop the stack. This builds the code that does that.

BuildSystemTrigger ( kOS.Safe.Compilation.KS.UserFunction func ) : void

Build the system trigger to go with a user function (lock) such as LOCK STEERING or LOCK THROTTLE

CompileProgram ( ParseTree tree ) : void
ConcatenateNodes ( ParseNode node ) : string

Create a unique string out of a sub-branch of the parse tree that can be used to uniquely identify it. The purpose is so that two sub-branches of the parse tree can be compared to see if they are the exact same code as each other.

ConcatenateNodesRecurse ( ParseNode node ) : string
CreateAppropriateStoreCode ( StorageModifier kind, bool lazyGlobal ) : Opcode

Make the right sort of opcodestore-ish opcode for what storage mode we're in.

DepthFirstLeftSearch ( ParseNode node, TokenType tokType ) : ParseNode

Perform a depth-first leftmost search of the parse tree from the starting point given to find the first occurrence of a node of the given token type.
This is intended as a way to make code that might be a bit more robustly able to handle shifts and adjustments to the parse grammar in the TinyPG file.
Instead of assuming "I know that array nodes are always one level underneath function nodes", it instead lets you say "Get the array node version of this node, no matter how many levels down it may be."
This is needed because TinyPG's LL(1) limitations made it so we had to define things like "we're going to call this node a 'function' even though it might not actually be because the "(..)" part of the syntax is optional. In reality it's *potentially* a function, or maybe actually an array, or an identifier.
This method is intended to let you descend however far down is required to get the node in the sort of context you're looking for.

EndScope ( ParseNode node, bool withPopScope = true ) : void

Insert the Opcode to finish a lexical scope Call upon every close brace "}" Should this code insert its own popscope. Only say false when you intend to immediately do a return statement and have the return statement be responsible for the popscope itself.

FindArgBottomSpot ( ParseNode node ) : int

When parsing a function, we need to mark the spot where the lastmost PARAMETER statement occurred, so it knows that that's the point during runtime where it should assert all the arguments passed in have been consumed by the function.

This is done by inserting a fake extra __ARGBOTTOM "statement" into the parse tree just after the last parameter, or if no parameters existed then right at the very top.

FindExistingUserFunction ( string funcIdentifier, ParseNode node ) : kOS.Safe.Compilation.KS.UserFunction

Much like UserFunctionCollection.GetUserFunction(), except that it won't generate a function if one doesn't exist. Instead it will try to walk up the parent scopes until it finds a func or lock with the given name. If it cannot find an existing function, it will return null rather than make one.

GetContainingBlockNode ( ParseNode node ) : ParseNode

Get the instruction_block this node is immediately inside of. Gives a null if the node isn't in one (it's global).

GetContainingScopeId ( ParseNode node ) : Int16

Walk up the parent chain finding the first instance of a ParseNode for which a scope ID has been assigned to it, and return that scope ID. Returns 0 (the global scope) when no hit was found.
That will usually be the containing instruction_block braces, but might not be, if dealing with file scoping, or the hidden extra scopes of FOR loops and so on.

GetIdentifierText ( ParseNode node ) : string
GetLineCol ( ParseNode node ) : kOS.Safe.Compilation.KS.LineCol

Get a line number and column for a given parse node. Handles the fact that TinyPG does not provide line and col information for all nodes - just the terminals. This means if you, say, ask for the line or column of a complex node like an expression, you get the bogus answer 0,0 back from TinyPG normally. This method performs a leftmost walk of the parse tree to get the first instance where a token exists with actual line and column information populated, and returns that.

GetNextLabel ( bool increment ) : string
GetReturnNestLevel ( ) : int
GetStorageModifierFor ( ParseNode node ) : StorageModifier
GetStorageModifierForDeclare ( ParseNode node ) : StorageModifier
GetUserFunctionWithScopeWalk ( string identifier, ParseNode node ) : kOS.Safe.Compilation.KS.UserFunction

Get the User function with the given the identifier, performing a scope walk from here up to the root of the parse tree until a hit is seen. If none are seen, then return null. This can only "see" the functions that are defined in this same compile, not ones from other scripts this script ran.

HasParameterStmtNested ( ParseNode node, bool &sawMandatoryParam ) : bool

Checks whether or not the given ParseNode contains a declare parameter statment inside it that pertains to this function. Note, parameters inside functions nested inside the current one don't count. This method performs a recursive walk.

While it does this walk, it also tests for whether or not there exists a non-defaulted parameter after a defaulted one, which is illegal and throws an error.

IdentifyUserFunctions ( ParseNode node ) : void
InitCompileFlags ( ) : void
IsDefineFunctionStatement ( ParseNode node ) : bool
IsInsideDefineFunctionStatement ( ParseNode node ) : bool
IsLastmostTrailerInTerm ( ParseNode node ) : bool

Returns true if this is the last most trailer term (array_trailer, suffix_trailer, or function_trailer) in a term inside a suffix rule of the parser. Does this by a tree walk to look for siblings to the right of me.

IsLockStatement ( ParseNode node ) : bool
IterateUserFunctions ( ParseNode node, Action action ) : void
LowercaseConversions ( ParseNode node ) : void

Lowercase every IDENTIFIER and FILEIDENT token in the parse.

NodeStartHousekeeping ( ParseNode node ) : void

Set the current line/column info and potentially also make a helpful debug trace useful when making syntax changes.

PeekTriggerKeepName ( ) : string
PopBreakList ( string label ) : void
PopReturnList ( ) : void
PopTriggerKeepName ( ) : string
PreProcess ( ParseTree tree ) : void
PreProcessChildNodes ( ParseNode node ) : void
PreProcessOnStatement ( ParseNode node ) : void
PreProcessStatements ( ParseNode node ) : void
PreProcessUserFunctionStatement ( ParseNode node ) : void
PreProcessWhenStatement ( ParseNode node ) : void
ProcessSetOperation ( ParseNode setThis, ParseNode toThis ) : void

For any statement of the form "SET THIS TO THAT", or "THIS ON" or "THIS OFF".

PushBreakList ( int nestLevel ) : void
PushReturnList ( ) : void
PushTriggerKeepName ( string newLabel ) : void
RearrangeLoopFromNode ( ParseNode node ) : void

Edit the parse branch for a loopfrom statement, rearranging its component parts into a simpler unrolled form.
When given this rule:

FROM {(init statements)} UNTIL expr STEP {(inc statements)} DO {(body statements)}

It will edit its own child nodes and transform them into a new parse tree branch as if this had been what was in the source code instead:

{ (init statements) UNTIL expr { (body statements) (inc statements) } }

Thus any variables declared inside (init statements) are in scope during the body of the loop.
The actual logic of doing an UNTIL loop will fall upon VisitUntilNode to deal with later in the compile.

RearrangeParseNodes ( ParseNode node ) : void

Some of the parse rules in Kerboscript may be implemented on the back of other rules. In this case all the compiler really does is just re-arrange a more complex parse rule to be expressed in the form of building blocks made of other simpler rules before continuing the compile that way.

TraverseScopeBranch ( ParseNode node ) : void

Because the compile occurs a bit out of order (doing the most deeply nested function first, then working out from there) it walks the scope nesting in the wrong order. Therefore before doing the compile, run through in one pass just recording the nesting levels and lexical parent tree of the scoping before we begin, so we can use that information later in the parse:

UnlockIdentifier ( kOS.Safe.Compilation.KS.UserFunction lockObject ) : void
VarIdentifierEndsWithIndex ( ParseNode node ) : bool

Check for if the rightmost thing in the var_identifier node is an array indexer. i.e. return true if the var_identifier is:
AAA:BBB[0], or
AAA[0],
but NOT if it's this:
AAA[0]:BBB
(Which does *contain* an array indexer, but not as the rightmost part of it. The rightmost part of it is the suffix term ":BBB".)

VarIdentifierEndsWithSuffix ( ParseNode node ) : bool

Check for if the rightmost thing in the var_identifier node is a suffix term. i.e. return true if the var_identifier is:
AAA:BBB, or
AAA[0]:BBB,
but NOT if it's this:
AAA:BBB[0].
(Which does *contain* a suffix, but not as the rightmost part of it. The rightmost part of it is the array indexer "[0]".)

VisitActualArray ( ParseNode node ) : void

Do the work for array index references. It assumes the array object has already been pushed on top of the stack so there's no reason to read that from the node's children. It just reads the indexing part.

VisitActualFunction ( ParseNode node, bool isDirect, string directName = "" ) : void

Do the work for function calls.

VisitAddStatement ( ParseNode node ) : void
VisitAnd ( ParseNode node ) : void
VisitArgList ( ParseNode node ) : void
VisitArgListReversed ( ParseNode node ) : void
VisitAtom ( ParseNode node ) : void
VisitBreakStatement ( ParseNode node ) : void
VisitChildNodes ( ParseNode node ) : void
VisitClearStatement ( ParseNode node ) : void
VisitComparator ( ParseNode node ) : void
VisitCompileStatement ( ParseNode node ) : void
VisitCopyStatement ( ParseNode node ) : void
VisitDeclareOneParameter ( StorageModifier whereToStore, ParseNode identifierNode, ParseNode expressionNode ) : void

Process a single parameter from the parameter list for a function or program. i.e. if encountering the statement "DECLARE PARAMETER AA, BB, CC is 0." , then this method needs to be called 3 times, once for AA, once for BB, and once for "CC is 0":

VisitDeclareStatement ( ParseNode node ) : void
VisitDeleteStatement ( ParseNode node ) : void
VisitDiv ( ParseNode node ) : void
VisitDouble ( ParseNode node ) : void
VisitEditStatement ( ParseNode node ) : void
VisitExpr ( ParseNode node ) : void

The outermost expression level, which may be a normal expression, or may be an anonymous function, depending of if it's got braces.

VisitExpressionChain ( ParseNode node ) : void

Performs the work for a number of different expressions that all share the following universal basic properties:
- They contain optional binary operators.
- The terms are all at the same precedence level.
- Because of the tie of precedence level, the terms are to be evaluated left-to-right.
- No special extra work is needed, such that simply doing "push expr1, push expr2, then do operator" is all that's needed.

Examples:
5 + 4 - x + 2 // because + and - are in the same parse rule, these all get the same flat precedence.
x * y * z
In cases like that where all the operators "tie", the entire chain of terms lives in the same ParseNode,
and we have to unroll those terms and presume left-to-right precedence. That is what this method does.

VisitFileIdent ( ParseNode node ) : void
VisitForStatement ( ParseNode node ) : void
VisitIdentifier ( ParseNode node ) : void
VisitIdentifierLedExpression ( ParseNode node ) : void
VisitIdentifierLedStatement ( ParseNode node ) : void
VisitIfStatement ( ParseNode node ) : void
VisitInstructionBlock ( ParseNode node ) : void
VisitInteger ( ParseNode node ) : void
VisitListStatement ( ParseNode node ) : void
VisitLockStatement ( ParseNode node, StorageModifier whereToStore ) : void
VisitLogStatement ( ParseNode node ) : void
VisitMult ( ParseNode node ) : void
VisitNode ( ParseNode node ) : void
VisitNumber ( ParseNode node ) : void
VisitOnOffTrailer ( ParseNode node ) : void
VisitOnStatement ( ParseNode node ) : void
VisitOr ( ParseNode node ) : void
VisitPlusMinus ( ParseNode node ) : void
VisitPower ( ParseNode node ) : void
VisitPreserveStatement ( ParseNode node ) : void
VisitPrintStatement ( ParseNode node ) : void
VisitRebootStatement ( ParseNode node ) : void
VisitRemoveStatement ( ParseNode node ) : void
VisitRenameStatement ( ParseNode node ) : void
VisitReturnStatement ( ParseNode node ) : void
VisitRunStatement ( ParseNode node ) : void

This one rule handles run_stmt, runpath_stmt, and runoncepath_stmt's. They're all nearly the same thing, but with slightly different syntaces.

VisitSciNumber ( ParseNode node ) : void
VisitSetStatement ( ParseNode node ) : void
VisitShortCircuitBoolean ( ParseNode node ) : void

Handles the short-circuit logic of boolean OR and boolean AND chains. It is like VisitExpressionChain (see elsewhere) but in this case it has the special logic to short circuit and skip executing the righthand expression if it can. (The generic VisitExpressionXhain always evaluates both the left and right sides of the operator first, then does the operation).

VisitShutdownStatement ( ParseNode node ) : void
VisitStageStatement ( ParseNode node ) : void
VisitStartStatement ( ParseNode node ) : void
VisitString ( ParseNode node ) : void
VisitSuffix ( ParseNode node ) : void
VisitSwitchStatement ( ParseNode node ) : void
VisitToggleStatement ( ParseNode node ) : void
VisitTrueFalse ( ParseNode node ) : void
VisitUnaryExpression ( ParseNode node ) : void
VisitUnlockStatement ( ParseNode node ) : void
VisitUnsetStatement ( ParseNode node ) : void
VisitUntilStatement ( ParseNode node ) : void
VisitVarIdentifier ( ParseNode node ) : void
VisitVariableNode ( ParseNode node ) : void
VisitWaitStatement ( ParseNode node ) : void
VisitWhenStatement ( ParseNode node ) : void

Method Details

Compile() public method

public Compile ( int startLineNum, ParseTree tree, Context context, CompilerOptions options ) : CodePart
startLineNum int
tree ParseTree
context Context
options CompilerOptions
return CodePart

VisitDirective() public method

public VisitDirective ( ParseNode node ) : void
node ParseNode
return void

VisitLazyGlobalDirective() public method

public VisitLazyGlobalDirective ( ParseNode node ) : void
node ParseNode
return void