123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353 |
- /*++
- Copyright (c) 2016 Minoca Corp.
- This file is licensed under the terms of the GNU General Public License
- version 3. Alternative licensing terms are available. Contact
- info@minocacorp.com for details. See the LICENSE file at the root of this
- project for complete licensing information.
- Module Name:
- compvar.c
- Abstract:
- This module implements variable related support for compiling Chalk
- source into bytecode.
- Author:
- Evan Green 9-Jun-2016
- Environment:
- C
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <stdio.h>
- #include "chalkp.h"
- #include <minoca/lib/status.h>
- #include <minoca/lib/yy.h>
- #include "compiler.h"
- #include "lang.h"
- #include "compsup.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- CK_SYMBOL_INDEX
- CkpFindUpvalue (
- PCK_COMPILER Compiler,
- PCSTR Name,
- UINTN Length
- );
- CK_SYMBOL_INDEX
- CkpAddUpvalue (
- PCK_COMPILER Compiler,
- BOOL IsLocal,
- CK_SYMBOL_INDEX Symbol
- );
- CK_SYMBOL_INDEX
- CkpResolveLocal (
- PCK_COMPILER Compiler,
- PCSTR Name,
- UINTN Length
- );
- CK_SYMBOL_INDEX
- CkpFindFunctionDeclaration (
- PCK_COMPILER Compiler,
- PCK_FUNCTION_SIGNATURE Signature,
- BOOL Remove
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // ------------------------------------------------------------------ Functions
- //
- CK_SYMBOL_INDEX
- CkpDeclareMethod (
- PCK_COMPILER Compiler,
- PCK_FUNCTION_SIGNATURE Signature,
- BOOL IsStatic,
- PLEXER_TOKEN NameToken,
- PSTR Name,
- UINTN Length
- )
- /*++
- Routine Description:
- This routine declares a method with the given signature, giving it a slot
- in the giant global method table, and giving it a slot in the class methods.
- Arguments:
- Compiler - Supplies a pointer to the compiler.
- Signature - Supplies a pointer to the function signature information.
- IsStatic - Supplies a boolean indicating if this is a static method or not.
- NameToken - Supplies a pointer to the function name token, for non-method
- functions.
- Name - Supplies a pointer to the signature string.
- Length - Supplies the length of the signature string, not including the
- null terminator.
- Return Value:
- Returns the index into the table of methods for this function's signature.
- --*/
- {
- PCK_CLASS_COMPILER EnclosingClass;
- CK_SYMBOL_INDEX Index;
- PCK_INT_ARRAY MethodArray;
- PSTR StaticString;
- CK_SYMBOL_INDEX Symbol;
- //
- // If there's no enclosing class, then this is a local or global function
- // being declared. Create a variable with its name.
- //
- EnclosingClass = Compiler->EnclosingClass;
- if (EnclosingClass == NULL) {
- CK_ASSERT(IsStatic == FALSE);
- //
- // First try to find an existing declaration.
- //
- Symbol = CkpFindFunctionDeclaration(Compiler, Signature, TRUE);
- if (Symbol != -1) {
- return Symbol;
- }
- return CkpDeclareVariable(Compiler, NameToken);
- }
- Symbol = CkpGetSignatureSymbol(Compiler, Signature);
- //
- // Make sure this class doesn't already have this method.
- //
- if (IsStatic != FALSE) {
- StaticString = "static ";
- MethodArray = &(EnclosingClass->StaticMethods);
- } else {
- StaticString = "";
- MethodArray = &(EnclosingClass->Methods);
- }
- for (Index = 0; Index < MethodArray->Count; Index += 1) {
- if (MethodArray->Data[Index] == Symbol) {
- CkpCompileError(Compiler,
- NULL,
- "Class %s already defines %smethod '%s'",
- EnclosingClass->Name->Value,
- StaticString,
- Name);
- break;
- }
- }
- CkpArrayAppend(Compiler->Parser->Vm, MethodArray, Symbol);
- return Symbol;
- }
- CK_SYMBOL_INDEX
- CkpGetSignatureSymbol (
- PCK_COMPILER Compiler,
- PCK_FUNCTION_SIGNATURE Signature
- )
- /*++
- Routine Description:
- This routine finds or creates a symbol index in the giant array of all
- method signatures.
- Arguments:
- Compiler - Supplies a pointer to the compiler.
- Signature - Supplies a pointer to the function signature information.
- Return Value:
- Returns the index into the table of methods for this function's signature.
- --*/
- {
- UINTN Length;
- CHAR Name[CK_MAX_METHOD_SIGNATURE];
- Length = sizeof(Name);
- CkpPrintSignature(Signature, Name, &Length);
- return CkpGetMethodSymbol(Compiler, Name, Length);
- }
- CK_SYMBOL_INDEX
- CkpGetMethodSymbol (
- PCK_COMPILER Compiler,
- PSTR Name,
- UINTN Length
- )
- /*++
- Routine Description:
- This routine returns the symbol for the given signature. If it did not
- previously exist, it is created.
- Arguments:
- Compiler - Supplies a pointer to the compiler.
- Name - Supplies a pointer to the method signature string.
- Length - Supplies the length of the method name, not including the null
- terminator.
- Return Value:
- Returns the index in the symbol table of method names.
- --*/
- {
- CK_SYMBOL_INDEX Symbol;
- Symbol = CkpStringTableEnsure(Compiler->Parser->Vm,
- &(Compiler->Function->Module->Strings),
- Name,
- Length);
- return Symbol;
- }
- PCK_CLASS_COMPILER
- CkpGetClassCompiler (
- PCK_COMPILER Compiler
- )
- /*++
- Routine Description:
- This routine walks up the compiler chain looking for the most recent class
- being defined.
- Arguments:
- Compiler - Supplies a pointer to the compiler.
- Return Value:
- Returns the innermost class being defined.
- NULL if a class is not currently being defined.
- --*/
- {
- while (Compiler != NULL) {
- if (Compiler->EnclosingClass != NULL) {
- return Compiler->EnclosingClass;
- }
- Compiler = Compiler->Parent;
- }
- return NULL;
- }
- VOID
- CkpLoadCoreVariable (
- PCK_COMPILER Compiler,
- PSTR Name
- )
- /*++
- Routine Description:
- This routine pushes one of the module-level variables from the core onto
- the stack.
- Arguments:
- Compiler - Supplies a pointer to the compiler.
- Name - Supplies a pointer to the core name to load.
- Return Value:
- None. The core variable is pushed onto the stack.
- --*/
- {
- CK_SYMBOL_INDEX Symbol;
- Symbol = CkpStringTableFind(&(Compiler->Parser->Module->VariableNames),
- Name,
- strlen(Name));
- CK_ASSERT(Symbol >= 0);
- CkpEmitShortOp(Compiler, CkOpLoadModuleVariable, Symbol);
- return;
- }
- VOID
- CkpLoadThis (
- PCK_COMPILER Compiler,
- PLEXER_TOKEN Token
- )
- /*++
- Routine Description:
- This routine loads the "this" local variable.
- Arguments:
- Compiler - Supplies a pointer to the compiler.
- Token - Supplies a pointer to the token, to point to in case it was an
- inappropriate scope for this.
- Return Value:
- None.
- --*/
- {
- CK_VARIABLE This;
- This = CkpResolveNonGlobal(Compiler, "this", 4);
- if (This.Index == -1) {
- CkpCompileError(Compiler, Token, "\"this\" used outside class method");
- return;
- }
- CkpLoadVariable(Compiler, This);
- return;
- }
- CK_VARIABLE
- CkpResolveNonGlobal (
- PCK_COMPILER Compiler,
- PCSTR Name,
- UINTN Length
- )
- /*++
- Routine Description:
- This routine finds the local variable or upvalue with the given name. It
- will not find module level variables.
- Arguments:
- Compiler - Supplies a pointer to the compiler.
- Name - Supplies the name of the variable to find.
- Length - Supplies the length of the name, not including the null terminator.
- Return Value:
- Returns the variable information on success.
- --*/
- {
- CK_VARIABLE Variable;
- Variable.Scope = CkScopeLocal;
- Variable.Index = CkpResolveLocal(Compiler, Name, Length);
- if (Variable.Index == -1) {
- Variable.Scope = CkScopeUpvalue;
- Variable.Index = CkpFindUpvalue(Compiler, Name, Length);
- if (Variable.Index == -1) {
- Variable.Scope = CkScopeInvalid;
- }
- }
- return Variable;
- }
- VOID
- CkpLoadVariable (
- PCK_COMPILER Compiler,
- CK_VARIABLE Variable
- )
- /*++
- Routine Description:
- This routine stores a variable with a previously defined symbol index in
- the current scope from the value at the top of the stack.
- Arguments:
- Compiler - Supplies a pointer to the compiler.
- Variable - Supplies the variable to load.
- Return Value:
- None.
- --*/
- {
- switch (Variable.Scope) {
- case CkScopeLocal:
- CkpLoadLocal(Compiler, Variable.Index);
- break;
- case CkScopeUpvalue:
- CkpEmitByteOp(Compiler, CkOpLoadUpvalue, Variable.Index);
- break;
- case CkScopeModule:
- CkpEmitShortOp(Compiler, CkOpLoadModuleVariable, Variable.Index);
- break;
- default:
- CK_ASSERT(FALSE);
- break;
- }
- return;
- }
- VOID
- CkpDefineVariable (
- PCK_COMPILER Compiler,
- CK_SYMBOL_INDEX Symbol
- )
- /*++
- Routine Description:
- This routine stores a variable with a previously defined symbol index in
- the current scope from the value at the top of the stack.
- Arguments:
- Compiler - Supplies a pointer to the compiler.
- Symbol - Supplies the symbol being defined.
- Return Value:
- None.
- --*/
- {
- //
- // If this is a local, the result of the initializer now on the stack is in
- // just the right place. Do nothing.
- //
- if (Compiler->ScopeDepth >= 0) {
- return;
- }
- //
- // Store the value into the module level variable.
- //
- CkpEmitShortOp(Compiler, CkOpStoreModuleVariable, Symbol);
- CkpEmitOp(Compiler, CkOpPop);
- return;
- }
- CK_SYMBOL_INDEX
- CkpDeclareVariable (
- PCK_COMPILER Compiler,
- PLEXER_TOKEN Token
- )
- /*++
- Routine Description:
- This routine creates a new variable slot in the current scope.
- Arguments:
- Compiler - Supplies a pointer to the compiler.
- Token - Supplies the token containing the name of the variable.
- Return Value:
- Returns the index of the new variable.
- --*/
- {
- CK_SYMBOL_INDEX Index;
- PCK_LOCAL Local;
- PCSTR Name;
- CK_SYMBOL_INDEX Symbol;
- if (Token->Size > CK_MAX_NAME) {
- CkpCompileError(Compiler, Token, "Name too long");
- return -1;
- }
- Name = Compiler->Parser->Source + Token->Position;
- if (Compiler->ScopeDepth == -1) {
- Symbol = CkpDefineModuleVariable(Compiler->Parser->Vm,
- Compiler->Parser->Module,
- Name,
- Token->Size,
- CK_NULL_VALUE);
- if (Symbol == -1) {
- CkpCompileError(Compiler,
- Token,
- "Module variable is already defined");
- } else if (Symbol == -2) {
- CkpCompileError(Compiler, Token, "Too many module level variables");
- }
- return Symbol;
- }
- //
- // Search for a local that might already be in this scope.
- //
- for (Index = Compiler->LocalCount - 1; Index >= 0; Index -= 1) {
- Local = &(Compiler->Locals[Index]);
- //
- // Stop looking if an outer scope is hit.
- //
- if (Local->Scope < Compiler->ScopeDepth) {
- break;
- }
- if ((Local->Length == Token->Size) &&
- (CkCompareMemory(Local->Name, Name, Local->Length) == 0)) {
- CkpCompileError(Compiler,
- Token,
- "Variable already declared in this scope");
- return Index;
- }
- }
- if (Compiler->LocalCount >= CK_MAX_LOCALS) {
- CkpCompileError(Compiler, Token, "Too many locals");
- return -1;
- }
- return CkpAddLocal(Compiler, Name, Token->Size);
- }
- VOID
- CkpPushScope (
- PCK_COMPILER Compiler
- )
- /*++
- Routine Description:
- This routine pushes a new local variable scope in the compiler.
- Arguments:
- Compiler - Supplies a pointer to the compiler.
- Return Value:
- None.
- --*/
- {
- Compiler->ScopeDepth += 1;
- return;
- }
- VOID
- CkpPopScope (
- PCK_COMPILER Compiler
- )
- /*++
- Routine Description:
- This routine pops the most recent local variable scope, and clears any
- knowledge of local variables defined at that scope.
- Arguments:
- Compiler - Supplies a pointer to the compiler.
- Return Value:
- None.
- --*/
- {
- CK_SYMBOL_INDEX Index;
- CK_SYMBOL_INDEX Popped;
- //
- // Discard declarations.
- //
- Index = Compiler->DeclarationCount - 1;
- while ((Index >= 0) &&
- (Compiler->Declarations[Index].Scope >= Compiler->ScopeDepth)) {
- Index -= 1;
- }
- Popped = CkpDiscardLocals(Compiler, Compiler->ScopeDepth);
- Compiler->LocalCount -= Popped;
- Compiler->StackSlots -= Popped;
- Compiler->ScopeDepth -= 1;
- return;
- }
- CK_SYMBOL_INDEX
- CkpDiscardLocals (
- PCK_COMPILER Compiler,
- LONG Depth
- )
- /*++
- Routine Description:
- This routine emits pop instructions to discard local variables up to a
- given depth. This doesn't actually undeclare the variables.
- Arguments:
- Compiler - Supplies a pointer to the compiler.
- Depth - Supplies the depth of locals to discard.
- Return Value:
- Returns the number of symbols popped.
- --*/
- {
- CK_SYMBOL_INDEX Index;
- CK_ASSERT(Compiler->ScopeDepth >= 0);
- Index = Compiler->LocalCount - 1;
- while ((Index >= 0) && (Compiler->Locals[Index].Scope >= Depth)) {
- //
- // If the local was closed over, make sure the upvalue gets closed as
- // this variable goes out of scope. Emit the byte directly as opposed
- // to the op because the stack effect shouldn't be tracked.
- //
- if (Compiler->Locals[Index].IsUpvalue != FALSE) {
- CkpEmitByte(Compiler, CkOpCloseUpvalue);
- } else {
- CkpEmitByte(Compiler, CkOpPop);
- }
- Index -= 1;
- }
- return Compiler->LocalCount - Index - 1;
- }
- VOID
- CkpLoadLocal (
- PCK_COMPILER Compiler,
- CK_SYMBOL_INDEX Symbol
- )
- /*++
- Routine Description:
- This routine loads a local variable and pushes it onto the stack.
- Arguments:
- Compiler - Supplies a pointer to the compiler.
- Symbol - Supplies the index of the local variable to load.
- Return Value:
- None.
- --*/
- {
- if (Symbol <= 8) {
- CkpEmitOp(Compiler, CkOpLoadLocal0 + Symbol);
- } else {
- CkpEmitByteOp(Compiler, CkOpLoadLocal, Symbol);
- }
- return;
- }
- CK_SYMBOL_INDEX
- CkpAddLocal (
- PCK_COMPILER Compiler,
- PCSTR Name,
- UINTN Length
- )
- /*++
- Routine Description:
- This routine unconditionally creates a new local variable with the given
- name.
- Arguments:
- Compiler - Supplies a pointer to the compiler.
- Name - Supplies a pointer to the name of the variable. This pointer will be
- used directly.
- Length - Supplies the length of the local in bytes, not including the
- null terminator.
- Return Value:
- Returns the index of the symbol.
- -1 on error.
- --*/
- {
- PCK_LOCAL Local;
- PVOID NewBuffer;
- UINTN NewCapacity;
- if (Compiler->LocalCount >= Compiler->LocalCapacity) {
- NewCapacity = Compiler->LocalCapacity * 2;
- NewBuffer = CkpReallocate(Compiler->Parser->Vm,
- Compiler->Locals,
- Compiler->LocalCapacity * sizeof(CK_LOCAL),
- NewCapacity * sizeof(CK_LOCAL));
- if (NewBuffer == NULL) {
- return -1;
- }
- Compiler->Locals = NewBuffer;
- Compiler->LocalCapacity = NewCapacity;
- }
- Local = &(Compiler->Locals[Compiler->LocalCount]);
- Local->Name = Name;
- Local->Length = Length;
- Local->Scope = Compiler->ScopeDepth;
- Local->IsUpvalue = FALSE;
- Compiler->LocalCount += 1;
- return Compiler->LocalCount - 1;
- }
- CK_SYMBOL_INDEX
- CkpAddConstant (
- PCK_COMPILER Compiler,
- CK_VALUE Constant
- )
- /*++
- Routine Description:
- This routine adds a new constant value to the current function.
- Arguments:
- Compiler - Supplies a pointer to the compiler.
- Constant - Supplies the constant to add.
- Return Value:
- Returns the index of the constant.
- -1 if the compiler already has an error.
- --*/
- {
- PCK_OBJECT Object;
- if (Compiler->Parser->Errors != 0) {
- return -1;
- }
- if (Compiler->Function->Constants.Count < CK_MAX_CONSTANTS) {
- if (CK_IS_OBJECT(Constant)) {
- Object = CK_AS_OBJECT(Constant);
- //
- // Strings belong in their own constant table.
- //
- CK_ASSERT(Object->Type != CkObjectString);
- CkpPushRoot(Compiler->Parser->Vm, Object);
- }
- CkpArrayAppend(Compiler->Parser->Vm,
- &(Compiler->Function->Constants),
- Constant);
- if (CK_IS_OBJECT(Constant)) {
- CkpPopRoot(Compiler->Parser->Vm);
- }
- } else {
- CkpCompileError(Compiler, NULL, "Too many constants");
- }
- return Compiler->Function->Constants.Count - 1;
- }
- CK_SYMBOL_INDEX
- CkpAddStringConstant (
- PCK_COMPILER Compiler,
- CK_VALUE Constant
- )
- /*++
- Routine Description:
- This routine adds a new string constant value to the current function.
- Arguments:
- Compiler - Supplies a pointer to the compiler.
- Constant - Supplies the string constant to add.
- Return Value:
- Returns the index of the constant.
- -1 if the compiler already has an error.
- --*/
- {
- CK_SYMBOL_INDEX Index;
- CK_ASSERT((CK_IS_OBJECT(Constant)) &&
- (CK_AS_OBJECT(Constant)->Type == CkObjectString));
- if (Compiler->Parser->Errors != 0) {
- return -1;
- }
- Index = CkpStringTableEnsureValue(Compiler->Parser->Vm,
- &(Compiler->Function->Module->Strings),
- Constant);
- if (Index >= CK_MAX_CONSTANTS) {
- CkpCompileError(Compiler, NULL, "Too many string constants");
- Index = -1;
- }
- return Index;
- }
- VOID
- CkpComplainIfAssigning (
- PCK_COMPILER Compiler,
- PLEXER_TOKEN Token,
- PSTR ExpressionName
- )
- /*++
- Routine Description:
- This routine complains if the compiler is in the middle of trying to get an
- lvalue for assignment.
- Arguments:
- Compiler - Supplies a pointer to the compiler.
- Token - Supplies a token that is part of the expression that is not an
- lvalue.
- ExpressionName - Supplies a pointer to the name of the expression.
- Return Value:
- None.
- --*/
- {
- if (Compiler->Assign != FALSE) {
- CkpCompileError(Compiler, Token, "%s is not an lvalue", ExpressionName);
- }
- return;
- }
- VOID
- CkpAddFunctionDeclaration (
- PCK_COMPILER Compiler,
- PCK_FUNCTION_SIGNATURE Signature,
- PLEXER_TOKEN NameToken
- )
- /*++
- Routine Description:
- This routine adds a function declaration.
- Arguments:
- Compiler - Supplies a pointer to the compiler.
- Signature - Supplies the function signature.
- NameToken - Supplies the name token of the variable.
- Return Value:
- None.
- --*/
- {
- LONG Index;
- PVOID NewBuffer;
- ULONG NewCapacity;
- CK_SYMBOL_INDEX SignatureSymbol;
- CK_SYMBOL_INDEX Symbol;
- SignatureSymbol = CkpGetSignatureSymbol(Compiler, Signature);
- if (SignatureSymbol == -1) {
- return;
- }
- //
- // Make sure there's room for one more, even if it's not needed.
- //
- if (Compiler->DeclarationCount >= Compiler->DeclarationCapacity) {
- if (Compiler->DeclarationCount == 0) {
- NewCapacity = 8;
- } else {
- NewCapacity = Compiler->DeclarationCapacity * 2;
- }
- NewBuffer = CkpReallocate(
- Compiler->Parser->Vm,
- Compiler->Declarations,
- Compiler->DeclarationCapacity * sizeof(CK_FUNCTION_DECLARATION),
- NewCapacity * sizeof(CK_FUNCTION_DECLARATION));
- if (NewBuffer == NULL) {
- return;
- }
- Compiler->Declarations = NewBuffer;
- Compiler->DeclarationCapacity = NewCapacity;
- }
- for (Index = Compiler->DeclarationCount - 1; Index >= 0; Index -= 1) {
- //
- // If there's already a declaration, return it.
- //
- if ((Compiler->Declarations[Index].Signature == SignatureSymbol) &&
- (Compiler->Declarations[Index].Scope == Compiler->ScopeDepth)) {
- return;
- }
- //
- // Stop looking if a lower scope is hit.
- //
- if (Compiler->Declarations[Index].Scope < Compiler->ScopeDepth) {
- break;
- }
- }
- Index = Compiler->DeclarationCount;
- //
- // Add the new declaration. Push a null to instantiate the variable.
- //
- CkpEmitOp(Compiler, CkOpNull);
- Symbol = CkpDeclareVariable(Compiler, NameToken);
- CkpDefineVariable(Compiler, Symbol);
- Compiler->Declarations[Index].Signature = SignatureSymbol;
- Compiler->Declarations[Index].Scope = Compiler->ScopeDepth;
- Compiler->Declarations[Index].Symbol = Symbol;
- Compiler->DeclarationCount += 1;
- return;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- CK_SYMBOL_INDEX
- CkpFindUpvalue (
- PCK_COMPILER Compiler,
- PCSTR Name,
- UINTN Length
- )
- /*++
- Routine Description:
- This routine attempts to find an upvalue, and notes its use in the current
- compiler.
- Arguments:
- Compiler - Supplies a pointer to the compiler.
- Name - Supplies a pointer to the name of the variable.
- Length - Supplies the length of the upvalue in bytes, not including the
- null terminator.
- Return Value:
- Returns the index of the symbol.
- -1 on error.
- --*/
- {
- CK_SYMBOL_INDEX Symbol;
- //
- // If this is the top level compiler, then it's not there.
- //
- if (Compiler->Parent == NULL) {
- return -1;
- }
- //
- // Try to find it as a local in the parent function.
- //
- Symbol = CkpResolveLocal(Compiler->Parent, Name, Length);
- if (Symbol != -1) {
- //
- // Note that variable as an upvalue in the parent.
- //
- Compiler->Parent->Locals[Symbol].IsUpvalue = TRUE;
- return CkpAddUpvalue(Compiler, TRUE, Symbol);
- }
- //
- // Recurse to see if it's a variable in the enclosing function. This
- // recursion will create upvalues up the function definition stack.
- //
- Symbol = CkpFindUpvalue(Compiler->Parent, Name, Length);
- if (Symbol != -1) {
- return CkpAddUpvalue(Compiler, FALSE, Symbol);
- }
- //
- // The recursion went all the way up and didn't find anything.
- //
- return -1;
- }
- CK_SYMBOL_INDEX
- CkpAddUpvalue (
- PCK_COMPILER Compiler,
- BOOL IsLocal,
- CK_SYMBOL_INDEX Symbol
- )
- /*++
- Routine Description:
- This routine adds an upvalue to the compiler's current list of upvalues, or
- at least ensures it is already known in the compiler.
- Arguments:
- Compiler - Supplies a pointer to the compiler.
- IsLocal - Supplies a boolean indicating if the new upvalue closes over a
- local or another upvalue.
- Symbol - Supplies the variable index that is an upvalue.
- Return Value:
- Returns the index of the upvalue.
- -1 on error.
- --*/
- {
- CK_SYMBOL_INDEX Count;
- CK_SYMBOL_INDEX Index;
- PVOID NewBuffer;
- UINTN NewCapacity;
- PCK_COMPILER_UPVALUE Upvalue;
- Count = Compiler->Function->UpvalueCount;
- for (Index = 0; Index < Count; Index += 1) {
- Upvalue = &(Compiler->Upvalues[Index]);
- if ((Upvalue->Index == Symbol) && (Upvalue->IsLocal == IsLocal)) {
- return Index;
- }
- }
- if (Count >= Compiler->UpvalueCapacity) {
- NewCapacity = Compiler->UpvalueCapacity * 2;
- if (NewCapacity == 0) {
- NewCapacity = 32;
- }
- NewBuffer = CkpReallocate(
- Compiler->Parser->Vm,
- Compiler->Upvalues,
- Compiler->UpvalueCapacity * sizeof(CK_COMPILER_UPVALUE),
- NewCapacity * sizeof(CK_COMPILER_UPVALUE));
- if (NewBuffer == NULL) {
- return -1;
- }
- Compiler->Upvalues = NewBuffer;
- Compiler->UpvalueCapacity = NewCapacity;
- }
- Compiler->Upvalues[Count].IsLocal = IsLocal;
- Compiler->Upvalues[Count].Index = Symbol;
- Compiler->Function->UpvalueCount += 1;
- return Count;
- }
- CK_SYMBOL_INDEX
- CkpResolveLocal (
- PCK_COMPILER Compiler,
- PCSTR Name,
- UINTN Length
- )
- /*++
- Routine Description:
- This routine attempts to find a local variable.
- Arguments:
- Compiler - Supplies a pointer to the compiler.
- Name - Supplies a pointer to the name of the variable.
- Length - Supplies the length of the local in bytes, not including the
- null terminator.
- Return Value:
- Returns the index of the symbol.
- -1 on error.
- --*/
- {
- CK_SYMBOL_INDEX Index;
- //
- // Search in reverse order so that the most recently scoped variables are
- // found first.
- //
- for (Index = Compiler->LocalCount - 1;
- Index >= 0;
- Index -= 1) {
- if ((Compiler->Locals[Index].Length == Length) &&
- (CkCompareMemory(Compiler->Locals[Index].Name, Name, Length) ==
- 0)) {
- return Index;
- }
- }
- return -1;
- }
- CK_SYMBOL_INDEX
- CkpFindFunctionDeclaration (
- PCK_COMPILER Compiler,
- PCK_FUNCTION_SIGNATURE Signature,
- BOOL Remove
- )
- /*++
- Routine Description:
- This routine finds a function declaration.
- Arguments:
- Compiler - Supplies a pointer to the compiler.
- Signature - Supplies the function signature.
- Remove - Supplies a boolean indicating whether to remove the declaration
- or not. TRUE is supplied when the function is being defined.
- Return Value:
- Returns the variable index for the function in the current scope.
- --*/
- {
- ULONG Index;
- CK_SYMBOL_INDEX SignatureSymbol;
- SignatureSymbol = CkpGetSignatureSymbol(Compiler, Signature);
- if (SignatureSymbol == -1) {
- return -1;
- }
- for (Index = 0; Index < Compiler->DeclarationCount; Index += 1) {
- if ((Compiler->Declarations[Index].Signature == SignatureSymbol) &&
- (Compiler->Declarations[Index].Scope == Compiler->ScopeDepth)) {
- if (Remove != FALSE) {
- Compiler->Declarations[Index].Signature = -1;
- }
- return Compiler->Declarations[Index].Symbol;
- }
- //
- // Stop looking if a lower scope is hit.
- //
- if (Compiler->Declarations[Index].Scope < Compiler->ScopeDepth) {
- break;
- }
- }
- return -1;
- }
|