* origin/master: (93 commits)
Add support for dictionary creation (#277)
Add do-while statement (#276)
Add foreach loops (#275)
New compiler: array initialization (#274)
Disambiguator: figure out if label is a case statement dispatch selector, or should apply to a statement within the case dispatch group's block. (#273)
New compiler: Add support for case statements (#272)
Change "logical" to "bitwise". (#258)
Fix divide-by-zero errors, and mask FormatError if it were thrown in a destructor. (#271)
Add break and continue statements. (#270)
New compiler: assignment to local and global variables. (#269)
Add support for while loops (#268)
Optimize if statements, and emit module functions in legacy order (#267)
Optimizations: binary operators (#266)
Add binary operators (#265)
Add support for const declarations (#264)
Handle default parameter values, pass-by-name, and return statements in functions. (#263)
Add limited support for user functions (#262)
New compiler: add return and exit statements (#261)
Add support for if-then-else statements (#259)
OG compiler: set module to Mod_Basic when a token is an identifier (#257)
...
Adds:
- ast/DictionaryEntry: AST node for a key -> value pair in a dictionary initializdr
- ast/DictionaryInitializer: AST node for creating a new dictionary
- ast/UninitializedValue: AST node for an uninit object
Adds:
- ast/CaseDispatchDefaultSelector: AST node for a "default:" selector
- ast/CaseDispatchGroup: AST node for a collection of selectors and the code to execute
- ast/CaseDispatchGroups: AST node holding all groups in a case statement
- ast/CaseDispatchSelectors: AST node holding all selectors for one group
- ast/CaseStatement: AST node for a whole case statement
- codegen/CaseDispatchGroupVisitor: knows what to put in a case jump dispatch table
- codegen/CaseJumpDataBlock: knows how to build the entries in the data block
Also, detect multiple case selectors with the same value (or default). This is different from the OG compiler, which only detected duplicate `default:` selectors.
* Change name of "logical" operators AND, OR and XOR to "bitwise".
Co-authored-by: Admin-Yukiko <hopelivesproject@gmail.com>
Co-authored-by: Eric Swanson <eric.the.unicorn@gmail.com>
Adds:
- ast/AssignVariableConsume: AST node for assignment to a variable, while consuming the result
- optimizer/ValueConsumerOptimizer: Optimizes expressions where the resulting value will be consumed
Adds:
- analyzer/FlowControlScope: Registers a break/continue scope
- analyzer/FlowControlScopes: Registry for break/continue scopes
- ast/LabelableStatement: Base class for AST nodes that can be labelled (loops and case)
- ast/LoopStatement: Base class for AST nodes for loops (have a break and continue label)
- ast/WhileLoop: AST node for a while loop
1. Optimize if statements (parity with OG compiler):
- discard empty 'alternative' blocks
- optimize to the consequent if the predicate is a nonzero integer
- optimize to the alternative, or an empty block if there is none, if the predicate is a zero integer.
2. In comparison mode, emit module functions in the same order as the OG compiler.
This is because the OG compiler can emit declarations for module functions that it doesn't actually call, and in a different order than calls to actual module functions.
Adds:
- optimizer/BinaryOperatorOptimizer: optimizes expressions with a binary operator
- assignments will be handled by optimizer/AssignmentOptimizer
- optimizer/BinaryOperatorWithFloatOptimizer: optimizes binary operator expressions with a FloatValue left-hand side
- optimizer/BinaryOperatorWithIntegerOptimizer: optimizes binary operator expressions with an IntegerValue left-hand side
- optimizer/BinaryOperatorWithStringOptimizer: optimizes binary operator expressions with a StringValue left-hand side
Adds:
- analyzer/Constants: holds constant name -> value for lookup
- ast/ConstDeclaration: AST node for a const declaration
- optimizer/ConstValidator: validates that an optimized expression is valid to use as a constant.
the Optimizer converts Identifiers that refer to a constant to the optimized constant value.
Process function call parameters to account for:
- default parameter values
- passing parameters by name
Also handle return within a function (I left this out of the previous PR)
Adds:
- astbuilder/SimpleValueCloner: clones values that are valid as constants and parameter default values.
Adds:
- ast/UserFunction AST node for user-defined functions.
- astbuilder/AvailableUserFunction: reference to a parse tree for a user function.
- The AST builder only generates ASTs for user functions that are actually referenced.
- astbuilder/UserFunctionVisitor: visits (builds an AST for) a parse tree for a user function.
- This happens after the .src or .inc file has been otherwise processed, so this class serves to hook up the correct SourceFileIdentifier to the AST.
Add:
- ast/ExitStatement: AST node for the exit statement.
- ast/ReturnStatement: AST node for the return statement.
- only handles top-level returns and returns inside program declarations, which do the same thing: progend.
Adds:
- ast/Block: a block scope that allows declaring local variables
- ast/IfThenElseStatement: AST node for if..elseif..else..endif statements
- model/FlowControlLabel: provides an anchor for jumps or calls.
- Function calls, break statements, continue statements, and loops will all use these.
The OG compiler looks up function ids for most tokens, even when it doesn't need to. When this happens, it assigns the module id as the module of the function.
When the token is later found not to be a function call, the parser changes the id to TOK_IDENT and the type to TYP_OPERAND, but leaves the module id.
We can see this in the included script, which adds members, which have names that match module function names, to a struct.
This doesn't cause problems during execution because the executor ignores the type for the emitted instructions.
It does cause problems when comparing .ecl output for parity between the old compiler and the new compiler, because the new compiler does not look up every identifier to see if it's a function.
This change assigns module = Mod_Basic along with id and type for tokens that are identifiers.
Adds:
- analyzer/LocalVariableScope: tracks local variables created within a given scope.
- Instantiated on the stack during semantic analysis, this registers itself with LocalVariableScopes during construction and deregisters itself during destruction.
- Detects unused variables during deregistration
- analyzer/LocalVariableScopes: this is what LocalVariableScope registers with.
- keeps track of the stack of local scopes.
- can provide the current local scope, for var statements.
Other notes:
"Shadowed" variables: this is when a variable in one scope hides a variable in another, like so:
var a := 2;
if (a)
var a := 3;
a := 4;
endif
print(a); // still 2
"debug_variables": We'll use these later when writing debug files.
1) Made all module methods [[nodiscard]]. Glad to report no leaks were found. We should add the same to BObjects.
2) Protected members of NPCExecutorModule (were public before).
3) Added NPCExecutorModule::controlled_npc() so that osmod can access the npc's name and position.
4) Removed declarations for undefined functions:
- attributemod.h: mf_SetAttributeIntrinsicMod()
- osmod.h: mf_System_RPM()
- vitalmod.h: mf_SetVitalMaximumValue() and mf_SetVitalRegenRate()
Adds:
- UnaryOperator: AST node for unary operators -, ++, --, and so forth
- UnaryOperatorOptimizer: optimizes a unary operator with its operand
- now integer and float negation, and integer inversion
- later x[y]++ to a single instruction
Also:
- automatically include basic.em, which includes some parameter defaults like -1.
This allows the compiler to generate output for a hello, world script with the exact same .ecl output as the legacy compiler.
Adds support for var statements at the global level.
Adds:
- analyzer/Variables: keeps track of the variables in scope (either local or global).
- ast/Identifier: AST node for an identifier.
- The optimizer will replace constant identifiers with their constant value (in a later commit).
- The semantic analyzer will set the variable field for local or global variable identifiers.
- ast/VarStatement: AST node for a var statement.
- A single var statement will generate one VarStatement per variable declared.
- model/Variable: Describes a variable, including its index within its scope.
Adds:
- ast/Argument: AST node for an argument passed to a function.
- ast/FunctionCall: AST node for a function call.
- codegen/ModuleDeclarationRegistrar: The code generator registers module function declarations with this in order to determine module indexes and function indexes for instructions.
- model/FunctionLink: this is a reference either:
- from: a FunctionCall or a FunctionReference
- to: a ModuleFunctionDeclaration or a UserFunction
- optimizer/ReferencedFunctionGatherer: a visitor that determines which module functions and user functions are referenced, by looking at function calls and function references.
Also:
- CodeGenerator registers module functions
- InstructionGenerator generates code for function calls
- InstructionEmitter generates TOK_FUNC instructions
- StoredTokenDecoder decodes TOK_FUNC instructions
After all of this, the compiler can compile print("hello, world");
Adds enough to build the AST nodes for the module function declarations in a .em file.
Adds:
- Function: base class for module function declarations and user functions
- FunctionParameterDeclaration: declaration for a function parameter, as well as its default value if any
- FunctionParameterList: just a holder for function parameter declarations
- ModuleFunctionDeclaration: for function declarations in .em files
- FunctionResolver: hooks up function calls to module functions or user functions
- ModuleProcessor: a visitor for processing const declarations and module function declarations (const declarations are yet to come from the main branch)
* Update grammar
- add '=' to grammar so that we can report appropriate errors
- add elvis ?: operator
- add foreachIterableExpression to match old compiler (which only allows certain expressions)
- allow both byref and unused on the same function parameter
- rename methodCall -> functionCall
- rename memberCall -> methodCall
- add named parser rule for functionReference
- move everything that isn't expression(s) with operators into primary
- expression is now just the left-recursive rules and prefix operators
- add named parser rules for struct, dictionary, error, array initialization
- remove special-case for named parameters with := from function call argument, because it is ambiguous with assignment
- Moved array access, object member access, and object method calls to navigationSuffix
* Regen grammar
* Upgrade Vagrant setup to Ubuntu 20.04 (focal64)
* Add clang and clang-format.
Now build_tools.sh -c works too
* Update comment: refer to git repo, not SVN
* by default on windows the clib pch shouldnt be reused and instead rebuild
* activate reuse_pch for windows ci build
* changed pch header from public to private