forked from cosmonaut/wraith-lang
				
			Compare commits
	
		
			10 Commits 
		
	
	
		
			41bf2bece8
			...
			9adfaed54c
		
	
	| Author | SHA1 | Date | 
|---|---|---|
|  | 9adfaed54c | |
|  | a571edcf6d | |
|  | ea203e6c3c | |
|  | 61344f5b60 | |
|  | 506ee9ecad | |
|  | d9b01515eb | |
|  | 473b706ad9 | |
|  | 876e8deb6e | |
|  | 459a1dd3b7 | |
|  | abc82f381e | 
|  | @ -0,0 +1,166 @@ | |||
| --- | ||||
| Language:        Cpp | ||||
| # BasedOnStyle:  LLVM | ||||
| AccessModifierOffset: -2 | ||||
| AlignAfterOpenBracket: AlwaysBreak | ||||
| AlignConsecutiveMacros: None | ||||
| AlignConsecutiveAssignments: None | ||||
| AlignConsecutiveBitFields: None | ||||
| AlignConsecutiveDeclarations: None | ||||
| AlignEscapedNewlines: Right | ||||
| AlignOperands:   Align | ||||
| AlignTrailingComments: true | ||||
| AllowAllArgumentsOnNextLine: false | ||||
| AllowAllConstructorInitializersOnNextLine: true | ||||
| AllowAllParametersOfDeclarationOnNextLine: false | ||||
| AllowShortEnumsOnASingleLine: true | ||||
| AllowShortBlocksOnASingleLine: Never | ||||
| AllowShortCaseLabelsOnASingleLine: false | ||||
| AllowShortFunctionsOnASingleLine: All | ||||
| AllowShortLambdasOnASingleLine: All | ||||
| AllowShortIfStatementsOnASingleLine: Never | ||||
| AllowShortLoopsOnASingleLine: false | ||||
| AlwaysBreakAfterDefinitionReturnType: None | ||||
| AlwaysBreakAfterReturnType: None | ||||
| AlwaysBreakBeforeMultilineStrings: false | ||||
| AlwaysBreakTemplateDeclarations: MultiLine | ||||
| AttributeMacros: | ||||
|   - __capability | ||||
| BinPackArguments: false | ||||
| BinPackParameters: false | ||||
| BraceWrapping: | ||||
|   AfterCaseLabel:  false | ||||
|   AfterClass:      false | ||||
|   AfterControlStatement: Never | ||||
|   AfterEnum:       false | ||||
|   AfterFunction:   false | ||||
|   AfterNamespace:  false | ||||
|   AfterObjCDeclaration: false | ||||
|   AfterStruct:     false | ||||
|   AfterUnion:      false | ||||
|   AfterExternBlock: false | ||||
|   BeforeCatch:     false | ||||
|   BeforeElse:      false | ||||
|   BeforeLambdaBody: false | ||||
|   BeforeWhile:     false | ||||
|   IndentBraces:    false | ||||
|   SplitEmptyFunction: true | ||||
|   SplitEmptyRecord: true | ||||
|   SplitEmptyNamespace: true | ||||
| BreakBeforeBinaryOperators: None | ||||
| BreakBeforeConceptDeclarations: true | ||||
| BreakBeforeBraces: Allman | ||||
| BreakBeforeInheritanceComma: false | ||||
| BreakInheritanceList: BeforeColon | ||||
| BreakBeforeTernaryOperators: true | ||||
| BreakConstructorInitializersBeforeComma: false | ||||
| BreakConstructorInitializers: BeforeColon | ||||
| BreakAfterJavaFieldAnnotations: false | ||||
| BreakStringLiterals: true | ||||
| ColumnLimit:     80 | ||||
| CommentPragmas:  '^ IWYU pragma:' | ||||
| CompactNamespaces: false | ||||
| ConstructorInitializerAllOnOneLineOrOnePerLine: false | ||||
| ConstructorInitializerIndentWidth: 4 | ||||
| ContinuationIndentWidth: 4 | ||||
| Cpp11BracedListStyle: true | ||||
| DeriveLineEnding: true | ||||
| DerivePointerAlignment: false | ||||
| DisableFormat:   false | ||||
| EmptyLineBeforeAccessModifier: LogicalBlock | ||||
| ExperimentalAutoDetectBinPacking: false | ||||
| FixNamespaceComments: true | ||||
| ForEachMacros: | ||||
|   - foreach | ||||
|   - Q_FOREACH | ||||
|   - BOOST_FOREACH | ||||
| StatementAttributeLikeMacros: | ||||
|   - Q_EMIT | ||||
| IncludeBlocks:   Preserve | ||||
| IncludeCategories: | ||||
|   - Regex:           '^"(llvm|llvm-c|clang|clang-c)/' | ||||
|     Priority:        2 | ||||
|     SortPriority:    0 | ||||
|     CaseSensitive:   false | ||||
|   - Regex:           '^(<|"(gtest|gmock|isl|json)/)' | ||||
|     Priority:        3 | ||||
|     SortPriority:    0 | ||||
|     CaseSensitive:   false | ||||
|   - Regex:           '.*' | ||||
|     Priority:        1 | ||||
|     SortPriority:    0 | ||||
|     CaseSensitive:   false | ||||
| IncludeIsMainRegex: '(Test)?$' | ||||
| IncludeIsMainSourceRegex: '' | ||||
| IndentCaseLabels: false | ||||
| IndentCaseBlocks: false | ||||
| IndentGotoLabels: true | ||||
| IndentPPDirectives: None | ||||
| IndentExternBlock: AfterExternBlock | ||||
| IndentRequires:  false | ||||
| IndentWidth:     4 | ||||
| IndentWrappedFunctionNames: false | ||||
| InsertTrailingCommas: None | ||||
| JavaScriptQuotes: Leave | ||||
| JavaScriptWrapImports: true | ||||
| KeepEmptyLinesAtTheStartOfBlocks: true | ||||
| MacroBlockBegin: '' | ||||
| MacroBlockEnd:   '' | ||||
| MaxEmptyLinesToKeep: 1 | ||||
| NamespaceIndentation: None | ||||
| ObjCBinPackProtocolList: Auto | ||||
| ObjCBlockIndentWidth: 4 | ||||
| ObjCBreakBeforeNestedBlockParam: true | ||||
| ObjCSpaceAfterProperty: false | ||||
| ObjCSpaceBeforeProtocolList: true | ||||
| PenaltyBreakAssignment: 2 | ||||
| PenaltyBreakBeforeFirstCallParameter: 19 | ||||
| PenaltyBreakComment: 300 | ||||
| PenaltyBreakFirstLessLess: 120 | ||||
| PenaltyBreakString: 1000 | ||||
| PenaltyBreakTemplateDeclaration: 10 | ||||
| PenaltyExcessCharacter: 1000000 | ||||
| PenaltyReturnTypeOnItsOwnLine: 1000000 | ||||
| PenaltyIndentedWhitespace: 0 | ||||
| PointerAlignment: Right | ||||
| ReflowComments:  true | ||||
| SortIncludes:    true | ||||
| SortJavaStaticImport: Before | ||||
| SortUsingDeclarations: true | ||||
| SpaceAfterCStyleCast: false | ||||
| SpaceAfterLogicalNot: false | ||||
| SpaceAfterTemplateKeyword: true | ||||
| SpaceBeforeAssignmentOperators: true | ||||
| SpaceBeforeCaseColon: false | ||||
| SpaceBeforeCpp11BracedList: false | ||||
| SpaceBeforeCtorInitializerColon: true | ||||
| SpaceBeforeInheritanceColon: true | ||||
| SpaceBeforeParens: ControlStatements | ||||
| SpaceAroundPointerQualifiers: Default | ||||
| SpaceBeforeRangeBasedForLoopColon: true | ||||
| SpaceInEmptyBlock: false | ||||
| SpaceInEmptyParentheses: false | ||||
| SpacesBeforeTrailingComments: 1 | ||||
| SpacesInAngles:  false | ||||
| SpacesInConditionalStatement: false | ||||
| SpacesInContainerLiterals: true | ||||
| SpacesInCStyleCastParentheses: false | ||||
| SpacesInParentheses: false | ||||
| SpacesInSquareBrackets: false | ||||
| SpaceBeforeSquareBrackets: false | ||||
| BitFieldColonSpacing: Both | ||||
| Standard:        Latest | ||||
| StatementMacros: | ||||
|   - Q_UNUSED | ||||
|   - QT_REQUIRE_VERSION | ||||
| TabWidth:        8 | ||||
| UseCRLF:         false | ||||
| UseTab:          Never | ||||
| WhitespaceSensitiveMacros: | ||||
|   - STRINGIZE | ||||
|   - PP_STRINGIZE | ||||
|   - BOOST_PP_STRINGIZE | ||||
|   - NS_SWIFT_NAME | ||||
|   - CF_SWIFT_NAME | ||||
| ... | ||||
| 
 | ||||
|  | @ -41,12 +41,14 @@ add_executable( | |||
| 	# Source | ||||
| 	src/ast.h | ||||
| 	src/codegen.h | ||||
| 	src/identcheck.h | ||||
| 	src/parser.h | ||||
| 	src/validation.h | ||||
| 	src/util.h | ||||
|     src/ast.c | ||||
| 	src/codegen.c | ||||
| 	src/identcheck.c | ||||
| 	src/parser.c | ||||
| 	src/validation.c | ||||
| 	src/util.c | ||||
| 	src/main.c | ||||
| 	# Generated code | ||||
|     ${BISON_Parser_OUTPUTS} | ||||
|  |  | |||
|  | @ -0,0 +1,13 @@ | |||
| struct G { | ||||
|     Foo(t: bool): bool { | ||||
|         return t; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| struct Program { | ||||
|     static main(): int { | ||||
|         g: G = alloc G; | ||||
|         g.Foo(true); | ||||
|         return 0; | ||||
|     } | ||||
| } | ||||
|  | @ -54,6 +54,8 @@ struct Program | |||
|             myStruct.myInt = 4; | ||||
|         } | ||||
| 
 | ||||
|         return myStruct.myInt; | ||||
|         Console.PrintLine("%i", myStruct.myInt); | ||||
| 
 | ||||
|         return 0; | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -12,6 +12,7 @@ | |||
| "double"                    return DOUBLE; | ||||
| "string"                    return STRING; | ||||
| "bool"                      return BOOL; | ||||
| "MemoryAddress"             return MEMORYADDRESS; | ||||
| "struct"                    return STRUCT; | ||||
| "return"                    return RETURN; | ||||
| "static"                    return STATIC; | ||||
|  | @ -40,6 +41,7 @@ | |||
| ";"                         return SEMICOLON; | ||||
| ":"                         return COLON; | ||||
| "?"                         return QUESTION; | ||||
| "@"                         return AT; | ||||
| "("                         return LEFT_PAREN; | ||||
| ")"                         return RIGHT_PAREN; | ||||
| "["                         return LEFT_BRACKET; | ||||
|  |  | |||
|  | @ -25,6 +25,7 @@ extern FILE *yyin; | |||
| %token DOUBLE | ||||
| %token STRING | ||||
| %token BOOL | ||||
| %token MEMORYADDRESS | ||||
| %token STRUCT | ||||
| %token RETURN | ||||
| %token STATIC | ||||
|  | @ -54,6 +55,7 @@ extern FILE *yyin; | |||
| %token SEMICOLON | ||||
| %token COLON | ||||
| %token QUESTION | ||||
| %token AT | ||||
| %token LEFT_PAREN | ||||
| %token RIGHT_PAREN | ||||
| %token LEFT_BRACE | ||||
|  | @ -107,9 +109,17 @@ BaseType                : VOID | |||
|                         { | ||||
|                             $$ = MakePrimitiveTypeNode(Bool); | ||||
|                         } | ||||
|                         | MEMORYADDRESS | ||||
|                         { | ||||
|                             $$ = MakePrimitiveTypeNode(MemoryAddress); | ||||
|                         } | ||||
|                         | Identifier GenericArgumentClauseNonEmpty | ||||
|                         { | ||||
|                             $$ = MakeConcreteGenericTypeNode($1, $2); | ||||
|                         } | ||||
|                         | Identifier | ||||
|                         { | ||||
|                             $$ = MakeCustomTypeNode(yytext); | ||||
|                             $$ = MakeCustomTypeNode($1); | ||||
|                         } | ||||
|                         | REFERENCE LESS_THAN Type GREATER_THAN | ||||
|                         { | ||||
|  | @ -141,11 +151,40 @@ AccessExpression        : Identifier POINT AccessExpression | |||
|                             $$ = $1; | ||||
|                         } | ||||
| 
 | ||||
| SystemCallExpression    : AT Identifier | ||||
|                         { | ||||
|                             $$ = $2; | ||||
|                         } | ||||
| 
 | ||||
| Number                  : NUMBER | ||||
|                         { | ||||
|                             $$ = MakeNumberNode(yytext); | ||||
|                         } | ||||
| 
 | ||||
| FieldInit               : Identifier COLON Expression | ||||
|                         { | ||||
|                             $$ = MakeFieldInitNode($1, $3); | ||||
|                         } | ||||
| 
 | ||||
| StructInitFields        : FieldInit | ||||
|                         { | ||||
|                             $$ = StartStructInitFieldsNode($1); | ||||
|                         } | ||||
|                         | StructInitFields COMMA FieldInit | ||||
|                         { | ||||
|                             $$ = AddFieldInitNode($1, $3); | ||||
|                         } | ||||
|                         | | ||||
|                         { | ||||
|                             $$ = MakeEmptyFieldInitNode(); | ||||
|                         } | ||||
|                         ; | ||||
| 
 | ||||
| StructInitExpression    : Type LEFT_BRACE StructInitFields RIGHT_BRACE | ||||
|                         { | ||||
|                             $$ = MakeStructInitExpressionNode($1, $3); | ||||
|                         } | ||||
| 
 | ||||
| PrimaryExpression       : Number | ||||
|                         | STRING_LITERAL | ||||
|                         { | ||||
|  | @ -157,6 +196,7 @@ PrimaryExpression       : Number | |||
|                         } | ||||
|                         | FunctionCallExpression | ||||
|                         | AccessExpression | ||||
|                         | StructInitExpression | ||||
|                         ; | ||||
| 
 | ||||
| UnaryExpression         : BANG Expression | ||||
|  | @ -230,9 +270,13 @@ ReturnStatement         : RETURN Expression | |||
|                             $$ = MakeReturnVoidStatementNode(); | ||||
|                         } | ||||
| 
 | ||||
| FunctionCallExpression  : AccessExpression LEFT_PAREN Arguments RIGHT_PAREN | ||||
| FunctionCallExpression  : AccessExpression GenericArgumentClause LEFT_PAREN Arguments RIGHT_PAREN | ||||
|                         { | ||||
|                             $$ = MakeFunctionCallExpressionNode($1, $3); | ||||
|                             $$ = MakeFunctionCallExpressionNode($1, $4, $2); | ||||
|                         } | ||||
|                         | SystemCallExpression GenericArgumentClause LEFT_PAREN Arguments RIGHT_PAREN | ||||
|                         { | ||||
|                             $$ = MakeSystemCallExpressionNode($1, $4, $2); | ||||
|                         } | ||||
| 
 | ||||
| PartialStatement        : FunctionCallExpression | ||||
|  | @ -275,11 +319,11 @@ Statements              : Statement | |||
|                             $$ = AddStatement($1, $2); | ||||
|                         } | ||||
| 
 | ||||
| Arguments               : PrimaryExpression | ||||
| Arguments               : Expression | ||||
|                         { | ||||
|                             $$ = StartFunctionArgumentSequenceNode($1); | ||||
|                         } | ||||
|                         | Arguments COMMA PrimaryExpression | ||||
|                         | Arguments COMMA Expression | ||||
|                         { | ||||
|                             $$ = AddFunctionArgumentNode($1, $3); | ||||
|                         } | ||||
|  | @ -307,14 +351,63 @@ Body                    : LEFT_BRACE Statements RIGHT_BRACE | |||
|                             $$ = $2; | ||||
|                         } | ||||
| 
 | ||||
| FunctionSignature       : Identifier LEFT_PAREN SignatureArguments RIGHT_PAREN COLON Type | ||||
| GenericDeclaration      : Identifier | ||||
|                         { | ||||
|                             $$ = MakeFunctionSignatureNode($1, $6, $3, MakeFunctionModifiersNode(NULL, 0)); | ||||
|                             $$ = MakeGenericDeclarationNode($1, NULL); | ||||
|                         } | ||||
|                         | STATIC Identifier LEFT_PAREN SignatureArguments RIGHT_PAREN COLON Type | ||||
| 
 | ||||
| GenericDeclarations     : GenericDeclaration | ||||
|                         { | ||||
|                             $$ = StartGenericDeclarationsNode($1); | ||||
|                         } | ||||
|                         | GenericDeclarations COMMA GenericDeclaration | ||||
|                         { | ||||
|                             $$ = AddGenericDeclaration($1, $3); | ||||
|                         } | ||||
| 
 | ||||
| GenericDeclarationClause    : LESS_THAN GenericDeclarations GREATER_THAN | ||||
|                             { | ||||
|                                 $$ = $2; | ||||
|                             } | ||||
|                             | | ||||
|                             { | ||||
|                                 $$ = MakeEmptyGenericDeclarationsNode(); | ||||
|                             } | ||||
| 
 | ||||
| GenericArgument         : Type | ||||
|                         { | ||||
|                             $$ = MakeGenericArgumentNode($1); | ||||
|                         } | ||||
| 
 | ||||
| GenericArguments        : GenericArgument | ||||
|                         { | ||||
|                             $$ = StartGenericArgumentsNode($1); | ||||
|                         } | ||||
|                         | GenericArguments COMMA GenericArgument | ||||
|                         { | ||||
|                             $$ = AddGenericArgument($1, $3); | ||||
|                         } | ||||
| 
 | ||||
| GenericArgumentClauseNonEmpty   : LESS_THAN GenericArguments GREATER_THAN | ||||
|                                 { | ||||
|                                     $$ = $2; | ||||
|                                 } | ||||
|                                 ; | ||||
| 
 | ||||
| GenericArgumentClause   : GenericArgumentClauseNonEmpty | ||||
|                         | | ||||
|                         { | ||||
|                             $$ = MakeEmptyGenericArgumentsNode(); | ||||
|                         } | ||||
| 
 | ||||
| FunctionSignature       : Identifier GenericDeclarationClause LEFT_PAREN SignatureArguments RIGHT_PAREN COLON Type | ||||
|                         { | ||||
|                             $$ = MakeFunctionSignatureNode($1, $7, $4, MakeFunctionModifiersNode(NULL, 0), $2); | ||||
|                         } | ||||
|                         | STATIC Identifier GenericDeclarationClause LEFT_PAREN SignatureArguments RIGHT_PAREN COLON Type | ||||
|                         { | ||||
|                             Node *modifier = MakeStaticNode(); | ||||
|                             $$ = MakeFunctionSignatureNode($2, $7, $4, MakeFunctionModifiersNode(&modifier, 1)); | ||||
|                             $$ = MakeFunctionSignatureNode($2, $8, $5, MakeFunctionModifiersNode(&modifier, 1), $3); | ||||
|                         } | ||||
| 
 | ||||
| FunctionDeclaration     : FunctionSignature Body | ||||
|  | @ -322,9 +415,9 @@ FunctionDeclaration     : FunctionSignature Body | |||
|                             $$ = MakeFunctionDeclarationNode($1, $2); | ||||
|                         } | ||||
| 
 | ||||
| StructDeclaration       : STRUCT Identifier LEFT_BRACE Declarations RIGHT_BRACE | ||||
| StructDeclaration       : STRUCT Identifier GenericDeclarationClause LEFT_BRACE Declarations RIGHT_BRACE | ||||
|                         { | ||||
|                             $$ = MakeStructDeclarationNode($2, $4); | ||||
|                             $$ = MakeStructDeclarationNode($2, $5, $3); | ||||
|                         } | ||||
| 
 | ||||
| Declaration             : FunctionDeclaration | ||||
|  |  | |||
|  | @ -0,0 +1,59 @@ | |||
| struct Foo { | ||||
|     static Func2<U>(u: U) : U { | ||||
|         return u; | ||||
|     } | ||||
| 
 | ||||
|     static Func<T>(t: T): T { | ||||
|         foo: T = t; | ||||
|         return Foo.Func2(foo); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| struct MemoryBlock<T> | ||||
| { | ||||
| 	start: MemoryAddress; | ||||
| 	capacity: uint; | ||||
| 
 | ||||
| 	AddressOf(index: uint): MemoryAddress | ||||
|     { | ||||
|         return start + (index * @sizeof<T>()); | ||||
|     } | ||||
| 
 | ||||
|     Get(index: uint): T | ||||
|     { | ||||
|         return @dereference<T>(AddressOf(index)); | ||||
|     } | ||||
| 
 | ||||
|     Set(index: uint, value: T): void | ||||
|     { | ||||
|         @memcpy(AddressOf(index), @addr(value), @sizeof<T>()); | ||||
|     } | ||||
| 
 | ||||
|     Free(): void | ||||
|     { | ||||
|         @free(start); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| struct Program { | ||||
|     static Main(): int { | ||||
|         x: int = 4; | ||||
|         y: int = Foo.Func(x); | ||||
|         block: MemoryBlock<int> = MemoryBlock<int> | ||||
|         { | ||||
|             capacity: y, | ||||
|             start: @malloc(y * @sizeof<int>()) | ||||
|         }; | ||||
|         block.Set(0, 5); | ||||
|         block.Set(1, 3); | ||||
|         block.Set(2, 9); | ||||
|         block.Set(3, 100); | ||||
|         Console.PrintLine("%p", block.start); | ||||
|         Console.PrintLine("%i", block.Get(0)); | ||||
|         Console.PrintLine("%i", block.Get(1)); | ||||
|         Console.PrintLine("%i", block.Get(2)); | ||||
|         Console.PrintLine("%i", block.Get(3)); | ||||
|         block.Free(); | ||||
|         return 0; | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,15 @@ | |||
| struct Foo { | ||||
|     static Func(): void { | ||||
|         Func2(); | ||||
|     } | ||||
| 
 | ||||
|     static Func2(): void { | ||||
|         Func(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| struct Program { | ||||
|     static main(): int { | ||||
|         return 0; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										490
									
								
								src/ast.h
								
								
								
								
							
							
						
						
									
										490
									
								
								src/ast.h
								
								
								
								
							|  | @ -2,7 +2,15 @@ | |||
| #define WRAITH_AST_H | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| #include "identcheck.h" | ||||
| 
 | ||||
| /* -Wpedantic nameless union/struct silencing */ | ||||
| #ifndef WRAITHNAMELESS | ||||
| #ifdef __GNUC__ | ||||
| #define WRAITHNAMELESS __extension__ | ||||
| #else | ||||
| #define WRAITHNAMELESS | ||||
| #endif /* __GNUC__ */ | ||||
| #endif /* WRAITHNAMELESS */ | ||||
| 
 | ||||
| typedef enum | ||||
| { | ||||
|  | @ -11,10 +19,11 @@ typedef enum | |||
|     Assignment, | ||||
|     BinaryExpression, | ||||
|     Comment, | ||||
|     ConcreteGenericTypeNode, | ||||
|     CustomTypeNode, | ||||
|     Declaration, | ||||
|     DeclarationSequence, | ||||
|     Expression, | ||||
|     FieldInit, | ||||
|     ForLoop, | ||||
|     FunctionArgumentSequence, | ||||
|     FunctionCallExpression, | ||||
|  | @ -22,6 +31,11 @@ typedef enum | |||
|     FunctionModifiers, | ||||
|     FunctionSignature, | ||||
|     FunctionSignatureArguments, | ||||
|     GenericArgument, | ||||
|     GenericArguments, | ||||
|     GenericDeclaration, | ||||
|     GenericDeclarations, | ||||
|     GenericTypeNode, | ||||
|     Identifier, | ||||
|     IfStatement, | ||||
|     IfElseStatement, | ||||
|  | @ -34,6 +48,9 @@ typedef enum | |||
|     StaticModifier, | ||||
|     StringLiteral, | ||||
|     StructDeclaration, | ||||
|     StructInit, | ||||
|     StructInitFields, | ||||
|     SystemCall, | ||||
|     Type, | ||||
|     UnaryExpression | ||||
| } SyntaxKind; | ||||
|  | @ -63,7 +80,8 @@ typedef enum | |||
|     UInt, | ||||
|     Float, | ||||
|     Double, | ||||
|     String | ||||
|     String, | ||||
|     MemoryAddress | ||||
| } PrimitiveType; | ||||
| 
 | ||||
| typedef union | ||||
|  | @ -72,14 +90,25 @@ typedef union | |||
|     BinaryOperator binaryOperator; | ||||
| } Operator; | ||||
| 
 | ||||
| typedef struct TypeTag | ||||
| typedef struct TypeTag TypeTag; | ||||
| 
 | ||||
| typedef struct ConcreteGenericTypeTag | ||||
| { | ||||
|     char *name; | ||||
|     TypeTag **genericArguments; | ||||
|     uint32_t genericArgumentCount; | ||||
| } ConcreteGenericTypeTag; | ||||
| 
 | ||||
| struct TypeTag | ||||
| { | ||||
|     enum Type | ||||
|     { | ||||
|         Unknown, | ||||
|         Primitive, | ||||
|         Reference, | ||||
|         Custom | ||||
|         Custom, | ||||
|         Generic, | ||||
|         ConcreteGeneric | ||||
|     } type; | ||||
|     union | ||||
|     { | ||||
|  | @ -89,153 +118,350 @@ typedef struct TypeTag | |||
|         struct TypeTag *referenceType; | ||||
|         /* Valid when type = Custom. */ | ||||
|         char *customType; | ||||
|         /* Valid when type = Generic. */ | ||||
|         char *genericType; | ||||
|         /* Valid when type = ConcreteGeneric */ | ||||
|         ConcreteGenericTypeTag concreteGenericType; | ||||
|     } value; | ||||
| } TypeTag; | ||||
| }; | ||||
| 
 | ||||
| typedef struct Node | ||||
| typedef struct Node Node; | ||||
| 
 | ||||
| struct Node | ||||
| { | ||||
|     Node *parent; | ||||
|     SyntaxKind syntaxKind; | ||||
|     struct Node **children; | ||||
|     uint32_t childCount; | ||||
|     union | ||||
|     WRAITHNAMELESS union | ||||
|     { | ||||
|         UnaryOperator unaryOperator; | ||||
|         BinaryOperator binaryOperator; | ||||
|     } operator; | ||||
|     union | ||||
|     { | ||||
|         char *string; | ||||
|         uint64_t number; | ||||
|     } value; | ||||
|     PrimitiveType primitiveType; | ||||
|     TypeTag *typeTag; | ||||
|     IdNode *idLink; | ||||
| } Node; | ||||
|         struct | ||||
|         { | ||||
|             Node *accessee; | ||||
|             Node *accessor; | ||||
|         } accessExpression; | ||||
| 
 | ||||
| const char* SyntaxKindString(SyntaxKind syntaxKind); | ||||
|         struct | ||||
|         { | ||||
|             Node *type; | ||||
|         } allocExpression; | ||||
| 
 | ||||
|         struct | ||||
|         { | ||||
|             Node *left; | ||||
|             Node *right; | ||||
|         } assignmentStatement; | ||||
| 
 | ||||
|         struct | ||||
|         { | ||||
|             Node *left; | ||||
|             Node *right; | ||||
|             BinaryOperator operator; | ||||
|         } binaryExpression; | ||||
| 
 | ||||
|         struct | ||||
|         { | ||||
| 
 | ||||
|         } comment; | ||||
| 
 | ||||
|         struct | ||||
|         { | ||||
|             char *name; | ||||
|             Node *genericArguments; | ||||
|         } concreteGenericType; | ||||
| 
 | ||||
|         struct | ||||
|         { | ||||
|             char *name; | ||||
|         } customType; | ||||
| 
 | ||||
|         struct | ||||
|         { | ||||
|             Node *type; | ||||
|             Node *identifier; | ||||
|         } declaration; | ||||
| 
 | ||||
|         struct | ||||
|         { | ||||
|             Node **sequence; | ||||
|             uint32_t count; | ||||
|         } declarationSequence; | ||||
| 
 | ||||
|         struct | ||||
|         { | ||||
|             Node *identifier; | ||||
|             Node *expression; | ||||
|         } fieldInit; | ||||
| 
 | ||||
|         struct | ||||
|         { | ||||
|             Node *declaration; | ||||
|             Node *startNumber; | ||||
|             Node *endNumber; | ||||
|             Node *statementSequence; | ||||
|         } forLoop; | ||||
| 
 | ||||
|         struct | ||||
|         { | ||||
|             Node **sequence; | ||||
|             uint32_t count; | ||||
|         } functionArgumentSequence; | ||||
| 
 | ||||
|         struct | ||||
|         { | ||||
|             Node *identifier; /* FIXME: need better name */ | ||||
|             Node *argumentSequence; | ||||
|             Node *genericArguments; | ||||
|         } functionCallExpression; | ||||
| 
 | ||||
|         struct | ||||
|         { | ||||
|             Node *functionSignature; | ||||
|             Node *functionBody; | ||||
|         } functionDeclaration; | ||||
| 
 | ||||
|         struct | ||||
|         { | ||||
|             Node **sequence; | ||||
|             uint32_t count; | ||||
|         } functionModifiers; | ||||
| 
 | ||||
|         struct | ||||
|         { | ||||
|             Node *identifier; | ||||
|             Node *type; | ||||
|             Node *arguments; | ||||
|             Node *modifiers; | ||||
|             Node *genericDeclarations; | ||||
|         } functionSignature; | ||||
| 
 | ||||
|         struct | ||||
|         { | ||||
|             Node **sequence; | ||||
|             uint32_t count; | ||||
|         } functionSignatureArguments; | ||||
| 
 | ||||
|         struct | ||||
|         { | ||||
|             Node *type; | ||||
|         } genericArgument; | ||||
| 
 | ||||
|         struct | ||||
|         { | ||||
|             Node **arguments; | ||||
|             uint32_t count; | ||||
|         } genericArguments; | ||||
| 
 | ||||
|         struct | ||||
|         { | ||||
|             Node *identifier; | ||||
|             Node *constraint; | ||||
|         } genericDeclaration; | ||||
| 
 | ||||
|         struct | ||||
|         { | ||||
|             Node **declarations; | ||||
|             uint32_t count; | ||||
|         } genericDeclarations; | ||||
| 
 | ||||
|         struct | ||||
|         { | ||||
|             char *name; | ||||
|         } genericType; | ||||
| 
 | ||||
|         struct | ||||
|         { | ||||
|             char *name; | ||||
|         } identifier; | ||||
| 
 | ||||
|         struct | ||||
|         { | ||||
|             Node *expression; | ||||
|             Node *statementSequence; | ||||
|         } ifStatement; | ||||
| 
 | ||||
|         struct | ||||
|         { | ||||
|             Node *ifStatement; | ||||
|             Node *elseStatement; | ||||
|         } ifElseStatement; | ||||
| 
 | ||||
|         struct | ||||
|         { | ||||
|             uint64_t value; | ||||
|         } number; | ||||
| 
 | ||||
|         struct | ||||
|         { | ||||
|             PrimitiveType type; | ||||
|         } primitiveType; | ||||
| 
 | ||||
|         struct | ||||
|         { | ||||
|             Node *type; | ||||
|         } referenceType; | ||||
| 
 | ||||
|         struct | ||||
|         { | ||||
|             Node *expression; | ||||
|         } returnStatement; | ||||
| 
 | ||||
|         struct | ||||
|         { | ||||
| 
 | ||||
|         } returnVoidStatement; | ||||
| 
 | ||||
|         struct | ||||
|         { | ||||
|             Node **sequence; | ||||
|             uint32_t count; | ||||
|         } statementSequence; | ||||
| 
 | ||||
|         struct | ||||
|         { | ||||
| 
 | ||||
|         } staticModifier; /* FIXME: modifiers should just be an enum */ | ||||
| 
 | ||||
|         struct | ||||
|         { | ||||
|             char *string; | ||||
|         } stringLiteral; | ||||
| 
 | ||||
|         struct | ||||
|         { | ||||
|             Node *identifier; | ||||
|             Node *declarationSequence; | ||||
|             Node *genericDeclarations; | ||||
|         } structDeclaration; | ||||
| 
 | ||||
|         struct | ||||
|         { | ||||
|             Node *type; | ||||
|             Node *initFields; | ||||
|         } structInit; | ||||
| 
 | ||||
|         struct | ||||
|         { | ||||
|             Node **fieldInits; | ||||
|             uint32_t count; | ||||
|         } structInitFields; | ||||
| 
 | ||||
|         struct | ||||
|         { | ||||
|             Node *identifier; | ||||
|             Node *argumentSequence; | ||||
|             Node *genericArguments; | ||||
|         } systemCall; | ||||
| 
 | ||||
|         struct | ||||
|         { | ||||
|             Node *typeNode; | ||||
|         } type; /* FIXME: this needs a refactor */ | ||||
| 
 | ||||
|         struct | ||||
|         { | ||||
|             Node *child; | ||||
|             UnaryOperator operator; | ||||
|         } unaryExpression; | ||||
|     }; | ||||
|     TypeTag *typeTag; | ||||
| }; | ||||
| 
 | ||||
| const char *SyntaxKindString(SyntaxKind syntaxKind); | ||||
| 
 | ||||
| uint8_t IsPrimitiveType(Node *typeNode); | ||||
| Node* MakePrimitiveTypeNode( | ||||
|     PrimitiveType type | ||||
| ); | ||||
| Node* MakeCustomTypeNode( | ||||
|     char *string | ||||
| ); | ||||
| Node* MakeReferenceTypeNode( | ||||
|     Node *typeNode | ||||
| ); | ||||
| Node* MakeTypeNode( | ||||
|     Node *typeNode /* can be primitive, custom, or reference */ | ||||
| ); | ||||
| Node* MakeIdentifierNode( | ||||
|     const char *id | ||||
| ); | ||||
| Node* MakeNumberNode( | ||||
|     const char *numberString | ||||
| ); | ||||
| Node* MakeStringNode( | ||||
|     const char *string | ||||
| ); | ||||
| Node* MakeStaticNode(); | ||||
| Node* MakeFunctionModifiersNode( | ||||
|     Node **pModifierNodes, | ||||
|     uint32_t modifierCount | ||||
| ); | ||||
| Node* MakeUnaryNode( | ||||
|     UnaryOperator operator, | ||||
|     Node *child | ||||
| ); | ||||
| Node* MakeBinaryNode( | ||||
|     BinaryOperator operator, | ||||
|     Node *left, | ||||
|     Node *right | ||||
| ); | ||||
| Node* MakeDeclarationNode( | ||||
|     Node* typeNode, | ||||
|     Node* identifierNode | ||||
| ); | ||||
| Node* MakeAssignmentNode( | ||||
|     Node *left, | ||||
|     Node *right | ||||
| ); | ||||
| Node* StartStatementSequenceNode( | ||||
|     Node* statementNode | ||||
| ); | ||||
| Node* AddStatement( | ||||
|     Node* statementSequenceNode, | ||||
|     Node *statementNode | ||||
| ); | ||||
| Node* MakeReturnStatementNode( | ||||
|     Node *expressionNode | ||||
| ); | ||||
| Node* MakeReturnVoidStatementNode(); | ||||
| Node* StartFunctionSignatureArgumentsNode( | ||||
|     Node *argumentNode | ||||
| ); | ||||
| Node* AddFunctionSignatureArgumentNode( | ||||
|     Node *argumentsNode, | ||||
|     Node *argumentNode | ||||
| ); | ||||
| Node *MakePrimitiveTypeNode(PrimitiveType type); | ||||
| Node *MakeCustomTypeNode(Node *identifierNode); | ||||
| Node *MakeReferenceTypeNode(Node *typeNode); | ||||
| Node *MakeConcreteGenericTypeNode( | ||||
|     Node *identifierNode, | ||||
|     Node *genericArgumentsNode); | ||||
| Node *MakeTypeNode(Node *typeNode); | ||||
| Node *MakeIdentifierNode(const char *id); | ||||
| Node *MakeNumberNode(const char *numberString); | ||||
| Node *MakeStringNode(const char *string); | ||||
| Node *MakeStaticNode(); | ||||
| Node *MakeFunctionModifiersNode(Node **pModifierNodes, uint32_t modifierCount); | ||||
| Node *MakeUnaryNode(UnaryOperator operator, Node * child); | ||||
| Node *MakeBinaryNode(BinaryOperator operator, Node * left, Node *right); | ||||
| Node *MakeDeclarationNode(Node *typeNode, Node *identifierNode); | ||||
| Node *MakeAssignmentNode(Node *left, Node *right); | ||||
| Node *StartStatementSequenceNode(Node *statementNode); | ||||
| Node *AddStatement(Node *statementSequenceNode, Node *statementNode); | ||||
| Node *MakeReturnStatementNode(Node *expressionNode); | ||||
| Node *MakeReturnVoidStatementNode(); | ||||
| Node *StartFunctionSignatureArgumentsNode(Node *argumentNode); | ||||
| Node *AddFunctionSignatureArgumentNode(Node *argumentsNode, Node *argumentNode); | ||||
| Node *MakeEmptyFunctionSignatureArgumentsNode(); | ||||
| Node* MakeFunctionSignatureNode( | ||||
| Node *MakeFunctionSignatureNode( | ||||
|     Node *identifierNode, | ||||
|     Node* typeNode, | ||||
|     Node* argumentsNode, | ||||
|     Node* modifiersNode | ||||
| ); | ||||
| Node* MakeFunctionDeclarationNode( | ||||
|     Node* functionSignatureNode, | ||||
|     Node* functionBodyNode | ||||
| ); | ||||
| Node* MakeStructDeclarationNode( | ||||
|     Node *typeNode, | ||||
|     Node *argumentsNode, | ||||
|     Node *modifiersNode, | ||||
|     Node *genericArgumentsNode); | ||||
| Node *MakeFunctionDeclarationNode( | ||||
|     Node *functionSignatureNode, | ||||
|     Node *functionBodyNode); | ||||
| Node *MakeGenericDeclarationNode(Node *identifierNode, Node *constraintNode); | ||||
| Node *MakeEmptyGenericDeclarationsNode(); | ||||
| Node *StartGenericDeclarationsNode(Node *genericDeclarationNode); | ||||
| Node *AddGenericDeclaration( | ||||
|     Node *genericDeclarationsNode, | ||||
|     Node *genericDeclarationNode); | ||||
| Node *MakeGenericArgumentNode(Node *typeNode); | ||||
| Node *MakeEmptyGenericArgumentsNode(); | ||||
| Node *StartGenericArgumentsNode(Node *genericArgumentNode); | ||||
| Node *AddGenericArgument(Node *genericArgumentsNode, Node *genericArgumentNode); | ||||
| Node *MakeGenericTypeNode(char *name); | ||||
| Node *MakeStructDeclarationNode( | ||||
|     Node *identifierNode, | ||||
|     Node *declarationSequenceNode | ||||
| ); | ||||
| Node* StartDeclarationSequenceNode( | ||||
|     Node *declarationNode | ||||
| ); | ||||
| Node* AddDeclarationNode( | ||||
|     Node *declarationSequenceNode, | ||||
|     Node *declarationNode | ||||
| ); | ||||
| Node *StartFunctionArgumentSequenceNode( | ||||
|     Node *argumentNode | ||||
| ); | ||||
| Node *AddFunctionArgumentNode( | ||||
|     Node *argumentSequenceNode, | ||||
|     Node *argumentNode | ||||
| ); | ||||
|     Node *genericArgumentsNode); | ||||
| Node *StartDeclarationSequenceNode(Node *declarationNode); | ||||
| Node *AddDeclarationNode(Node *declarationSequenceNode, Node *declarationNode); | ||||
| Node *StartFunctionArgumentSequenceNode(Node *argumentNode); | ||||
| Node *AddFunctionArgumentNode(Node *argumentSequenceNode, Node *argumentNode); | ||||
| Node *MakeEmptyFunctionArgumentSequenceNode(); | ||||
| Node* MakeFunctionCallExpressionNode( | ||||
| Node *MakeFunctionCallExpressionNode( | ||||
|     Node *identifierNode, | ||||
|     Node *argumentSequenceNode | ||||
| ); | ||||
| Node* MakeAccessExpressionNode( | ||||
|     Node *accessee, | ||||
|     Node *accessor | ||||
| ); | ||||
| Node* MakeAllocNode( | ||||
|     Node *typeNode | ||||
| ); | ||||
| Node* MakeIfNode( | ||||
|     Node *expressionNode, | ||||
|     Node *statementSequenceNode | ||||
| ); | ||||
| Node* MakeIfElseNode( | ||||
|     Node *argumentSequenceNode, | ||||
|     Node *genericArgumentsNode); | ||||
| Node *MakeSystemCallExpressionNode( | ||||
|     Node *identifierNode, | ||||
|     Node *argumentSequenceNode, | ||||
|     Node *genericArgumentsNode); | ||||
| Node *MakeAccessExpressionNode(Node *accessee, Node *accessor); | ||||
| Node *MakeAllocNode(Node *typeNode); | ||||
| Node *MakeIfNode(Node *expressionNode, Node *statementSequenceNode); | ||||
| Node *MakeIfElseNode( | ||||
|     Node *ifNode, | ||||
|     Node *statementSequenceNode | ||||
|     Node *elseNode /* can be a conditional or a statement sequence */ | ||||
| ); | ||||
| Node* MakeForLoopNode( | ||||
| Node *MakeForLoopNode( | ||||
|     Node *identifierNode, | ||||
|     Node *startNumberNode, | ||||
|     Node *endNumberNode, | ||||
|     Node *statementSequenceNode | ||||
| ); | ||||
|     Node *statementSequenceNode); | ||||
| Node *MakeFieldInitNode(Node *identifierNode, Node *expressionNode); | ||||
| Node *StartStructInitFieldsNode(Node *fieldInitNode); | ||||
| Node *AddFieldInitNode(Node *structInitFieldsNode, Node *fieldInitNode); | ||||
| Node *MakeEmptyFieldInitNode(); | ||||
| Node *MakeStructInitExpressionNode(Node *typeNode, Node *structInitFieldsNode); | ||||
| 
 | ||||
| void PrintTree(Node *node, uint32_t tabCount); | ||||
| const char* SyntaxKindString(SyntaxKind syntaxKind); | ||||
| void PrintNode(Node *node, uint32_t tabCount); | ||||
| const char *SyntaxKindString(SyntaxKind syntaxKind); | ||||
| 
 | ||||
| TypeTag* MakeTypeTag(Node *node); | ||||
| char* TypeTagToString(TypeTag *tag); | ||||
| /* Helper function for applying a void function generically over the children of
 | ||||
|  * an AST node. Used for functions that need to traverse the entire tree but | ||||
|  * only perform operations on a subset of node types. Such functions can match | ||||
|  * the syntaxKinds relevant to their purpose and invoke this function in all | ||||
|  * other cases. */ | ||||
| void Recurse(Node *node, void (*func)(Node *)); | ||||
| 
 | ||||
| void LinkParentPointers(Node *node, Node *prev); | ||||
| 
 | ||||
| TypeTag *MakeTypeTag(Node *node); | ||||
| char *TypeTagToString(TypeTag *tag); | ||||
| uint8_t TypeTagEqual(TypeTag *typeTagA, TypeTag *typeTagB); | ||||
| 
 | ||||
| Node *LookupIdNode(Node *current, Node *prev, char *target); | ||||
| 
 | ||||
| #endif /* WRAITH_AST_H */ | ||||
|  |  | |||
							
								
								
									
										2255
									
								
								src/codegen.c
								
								
								
								
							
							
						
						
									
										2255
									
								
								src/codegen.c
								
								
								
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										328
									
								
								src/identcheck.c
								
								
								
								
							
							
						
						
									
										328
									
								
								src/identcheck.c
								
								
								
								
							|  | @ -1,328 +0,0 @@ | |||
| #include <stdbool.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdint.h> | ||||
| #include <string.h> | ||||
| 
 | ||||
| #include "ast.h" | ||||
| #include "identcheck.h" | ||||
| 
 | ||||
| IdNode* MakeIdNode(NodeType type, char *name, IdNode *parent) { | ||||
|     IdNode *node = (IdNode*)malloc(sizeof(IdNode)); | ||||
|     node->type = type; | ||||
|     node->name = strdup(name); | ||||
|     node->parent = parent; | ||||
|     node->childCount = 0; | ||||
|     node->childCapacity = 0; | ||||
|     node->children = NULL; | ||||
|     node->typeTag = NULL; | ||||
|     return node; | ||||
| } | ||||
| 
 | ||||
| void AddChildToNode(IdNode *node, IdNode *child) { | ||||
|     if (child == NULL) return; | ||||
| 
 | ||||
|     if (node->children == NULL) { | ||||
|         node->childCapacity = 2; | ||||
|         node->children = (IdNode**) malloc(sizeof(IdNode*) * node->childCapacity); | ||||
|     } else if (node->childCount == node->childCapacity) { | ||||
|         node->childCapacity *= 2; | ||||
|         node->children = (IdNode**) realloc(node->children, sizeof(IdNode*) * node->childCapacity); | ||||
|     } | ||||
| 
 | ||||
|     node->children[node->childCount] = child; | ||||
|     node->childCount += 1; | ||||
| } | ||||
| 
 | ||||
| IdNode* MakeIdTree(Node *astNode, IdNode *parent) { | ||||
|     uint32_t i; | ||||
|     IdNode *mainNode; | ||||
|     switch (astNode->syntaxKind) { | ||||
|         case Assignment: { | ||||
|             if (astNode->children[0]->syntaxKind == Declaration) { | ||||
|                 return MakeIdTree(astNode->children[0], parent); | ||||
|             } else { | ||||
|                 for (i = 0; i < astNode->childCount; i++) { | ||||
|                     AddChildToNode(parent, MakeIdTree(astNode->children[i], parent)); | ||||
|                 } | ||||
|                 return NULL; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         case IfStatement: { | ||||
|             mainNode = MakeIdNode(OrderedScope, "if", parent); | ||||
|             Node *clause = astNode->children[0]; | ||||
|             Node *stmtSeq = astNode->children[1]; | ||||
|             for (i = 0; i < clause->childCount; i++) { | ||||
|                 AddChildToNode(mainNode, MakeIdTree(clause->children[i], mainNode)); | ||||
|             } | ||||
|             for (i = 0; i < stmtSeq->childCount; i++) { | ||||
|                 AddChildToNode(mainNode, MakeIdTree(stmtSeq->children[i], mainNode)); | ||||
|             } | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         case IfElseStatement: { | ||||
|             Node *ifNode = astNode->children[0]; | ||||
|             Node *elseStmts = astNode->children[1]; | ||||
|             mainNode = MakeIdNode(OrderedScope, "if-else", parent); | ||||
|             IdNode *ifBranch = MakeIdTree(ifNode, mainNode); | ||||
|             IdNode *elseBranch = MakeIdNode(OrderedScope, "else", mainNode); | ||||
| 
 | ||||
|             AddChildToNode(mainNode, ifBranch); | ||||
|             for (i = 0; i < elseStmts->childCount; i++) { | ||||
|                 AddChildToNode(elseBranch, MakeIdTree(elseStmts->children[i], elseBranch)); | ||||
|             } | ||||
|             AddChildToNode(mainNode, elseBranch); | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         case ForLoop: { | ||||
|             Node *loopDecl = astNode->children[0]; | ||||
|             Node *loopBody = astNode->children[3]; | ||||
|             mainNode = MakeIdNode(OrderedScope, "for-loop", parent); | ||||
|             AddChildToNode(mainNode, MakeIdTree(loopDecl, mainNode)); | ||||
|             for (i = 0; i < loopBody->childCount; i++) { | ||||
|                 AddChildToNode(mainNode, MakeIdTree(loopBody->children[i], mainNode)); | ||||
|             } | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         case Declaration: { | ||||
|             mainNode = MakeIdNode(Variable, astNode->children[1]->value.string, parent); | ||||
|             mainNode->typeTag = MakeTypeTag(astNode); | ||||
|             astNode->children[1]->typeTag = mainNode->typeTag; | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         case StructDeclaration: { | ||||
|             Node *idNode = astNode->children[0]; | ||||
|             Node *declsNode = astNode->children[1]; | ||||
|             mainNode = MakeIdNode(Struct, idNode->value.string, parent); | ||||
|             mainNode->typeTag = MakeTypeTag(astNode); | ||||
|             for (i = 0; i < declsNode->childCount; i++) { | ||||
|                 AddChildToNode(mainNode, MakeIdTree(declsNode->children[i], mainNode)); | ||||
|             } | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         case FunctionDeclaration: { | ||||
|             Node *sigNode = astNode->children[0]; | ||||
|             Node *funcNameNode = sigNode->children[0]; | ||||
|             Node *funcArgsNode = sigNode->children[2]; | ||||
|             Node *bodyStatementsNode = astNode->children[1]; | ||||
|             mainNode = MakeIdNode(Function, funcNameNode->value.string, parent); | ||||
|             mainNode->typeTag = MakeTypeTag(astNode); | ||||
|             astNode->children[0]->children[0]->typeTag = mainNode->typeTag; | ||||
|             for (i = 0; i < funcArgsNode->childCount; i++) { | ||||
|                 AddChildToNode(mainNode, MakeIdTree(funcArgsNode->children[i], mainNode)); | ||||
|             } | ||||
|             for (i = 0; i < bodyStatementsNode->childCount; i++) { | ||||
|                 AddChildToNode(mainNode, MakeIdTree(bodyStatementsNode->children[i], mainNode)); | ||||
|             } | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         case DeclarationSequence: { | ||||
|             mainNode = MakeIdNode(UnorderedScope, "", parent); | ||||
|             for (i = 0; i < astNode->childCount; i++) { | ||||
|                 AddChildToNode(mainNode, MakeIdTree(astNode->children[i], mainNode)); | ||||
|             } | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         case Identifier: { | ||||
|             mainNode = MakeIdNode(Placeholder, astNode->value.string, parent); | ||||
|             IdNode *lookupNode = LookupId(mainNode, NULL, astNode->value.string); | ||||
|             if (lookupNode == NULL) { | ||||
|                 fprintf(stderr, "wraith: Could not find IdNode for id %s\n", astNode->value.string); | ||||
|                 TypeTag *tag = (TypeTag*)malloc(sizeof(TypeTag)); | ||||
|                 tag->type = Unknown; | ||||
|                 astNode->typeTag = tag; | ||||
|             } else { | ||||
|                 astNode->typeTag = lookupNode->typeTag; | ||||
|             } | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         default: { | ||||
|             for (i = 0; i < astNode->childCount; i++) { | ||||
|                 AddChildToNode(parent, MakeIdTree(astNode->children[i], parent)); | ||||
|             } | ||||
|             return NULL; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     astNode->idLink = mainNode; | ||||
|     return mainNode; | ||||
| } | ||||
| 
 | ||||
| void PrintIdNode(IdNode *node) { | ||||
|     if (node == NULL) { | ||||
|         fprintf(stderr, "wraith: Attempted to call PrintIdNode with null value.\n"); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     switch(node->type) { | ||||
|         case Placeholder: | ||||
|             printf("Placeholder (%s)\n", node->name); | ||||
|             break; | ||||
|         case OrderedScope: | ||||
|             printf("OrderedScope (%s)\n", node->name); | ||||
|             break; | ||||
|         case UnorderedScope: | ||||
|             printf("UnorderedScope (%s)\n", node->name); | ||||
|             break; | ||||
|         case Struct: | ||||
|             printf("%s : %s\n", node->name, TypeTagToString(node->typeTag)); | ||||
|             break; | ||||
|         case Function: | ||||
|             printf("%s : Function<%s>\n", node->name, TypeTagToString(node->typeTag)); | ||||
|             break; | ||||
|         case Variable: | ||||
|             printf("%s : %s\n", node->name, TypeTagToString(node->typeTag)); | ||||
|             break; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void PrintIdTree(IdNode *tree, uint32_t tabCount) { | ||||
|     if (tree == NULL) { | ||||
|         fprintf(stderr, "wraith: Attempted to call PrintIdTree on a null value.\n"); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     uint32_t i; | ||||
|     for (i = 0; i < tabCount; i++) { | ||||
|         printf("| "); | ||||
|     } | ||||
| 
 | ||||
|     PrintIdNode(tree); | ||||
| 
 | ||||
|     for (i = 0; i < tree->childCount; i++) { | ||||
|         PrintIdTree(tree->children[i], tabCount + 1); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int PrintAncestors(IdNode *node) { | ||||
|     if (node == NULL) return -1; | ||||
| 
 | ||||
|     int i; | ||||
|     int indent = 1; | ||||
|     indent += PrintAncestors(node->parent); | ||||
|     for (i = 0; i < indent; i++) { | ||||
|         printf(" "); | ||||
|     } | ||||
|     PrintIdNode(node); | ||||
|     return indent; | ||||
| } | ||||
| 
 | ||||
| IdNode* LookdownId(IdNode *root, NodeType targetType, char *targetName) { | ||||
|     if (root == NULL) { | ||||
|         fprintf(stderr, "wraith: Attempted to call LookdownId on a null value.\n"); | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     IdNode *result = NULL; | ||||
|     IdNode **frontier = (IdNode**)malloc(sizeof(IdNode*)); | ||||
|     frontier[0] = root; | ||||
|     uint32_t frontierCount = 1; | ||||
| 
 | ||||
|     while (frontierCount > 0) { | ||||
|         IdNode *current = frontier[0]; | ||||
| 
 | ||||
|         if (current->type == targetType && strcmp(current->name, targetName) == 0) { | ||||
|             result = current; | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         uint32_t i; | ||||
|         for(i = 1; i < frontierCount; i++) { | ||||
|             frontier[i-1] = frontier[i]; | ||||
|         } | ||||
|         size_t newSize = frontierCount + current->childCount - 1; | ||||
|         if (frontierCount != newSize) { | ||||
|             frontier = (IdNode**) realloc(frontier, sizeof(IdNode*) * newSize); | ||||
|         } | ||||
|         for (i = 0; i < current->childCount; i++) { | ||||
|             frontier[frontierCount + i - 1] = current->children[i]; | ||||
|         } | ||||
|         frontierCount = newSize; | ||||
|     } | ||||
| 
 | ||||
|     free(frontier); | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| bool ScopeHasOrdering(IdNode *node) { | ||||
|     switch (node->type) { | ||||
|         case OrderedScope: | ||||
|         case Function: | ||||
|         case Variable: /* this is only technically true */ | ||||
|             return true; | ||||
|         default: | ||||
|             return false; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| IdNode* LookupId(IdNode *node, IdNode *prev, char *target) { | ||||
|     if (node == NULL) { | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     if (strcmp(node->name, target) == 0 && node->type != Placeholder) { | ||||
|         return node; | ||||
|     } | ||||
| 
 | ||||
|     /* If this is the start of our search, we should not attempt to look at child nodes. Only
 | ||||
|      * looking up the scope tree is valid at this point. | ||||
|      * | ||||
|      * This has the notable side-effect that this function will return NULL if you attempt to look | ||||
|      * up a struct's internals starting from the node representing the struct itself. This is | ||||
|      * because an IdNode corresponds to the location *where an identifier is first declared.* Thus, | ||||
|      * an identifier has no knowledge of identifiers declared "inside" of it. | ||||
|      */ | ||||
|     if (prev == NULL) { | ||||
|         return LookupId(node->parent, node, target); | ||||
|     } | ||||
| 
 | ||||
|     /* If the current node forms an ordered scope then we want to prevent ourselves from looking
 | ||||
|      * up identifiers declared after the scope we have just come from. | ||||
|      */ | ||||
|     uint32_t idxLimit; | ||||
|     if (ScopeHasOrdering(node)) { | ||||
|         uint32_t i; | ||||
|         for (i = 0, idxLimit = 0; i < node->childCount; i++, idxLimit++) { | ||||
|             if (node->children[i] == prev) { | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|     } else { | ||||
|         idxLimit = node->childCount; | ||||
|     } | ||||
| 
 | ||||
|     uint32_t i; | ||||
|     for (i = 0; i < idxLimit; i++) { | ||||
|         IdNode *child = node->children[i]; | ||||
|         if (child == prev || child->type == Placeholder) { | ||||
|             /* Do not inspect the node we just came from or placeholders. */ | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         if (strcmp(child->name, target) == 0) { | ||||
|             return child; | ||||
|         } | ||||
| 
 | ||||
|         if (child->type == Struct) { | ||||
|             uint32_t j; | ||||
|             for (j = 0; j < child->childCount; j++) { | ||||
|                 IdNode *grandchild = child->children[j]; | ||||
|                 if (strcmp(grandchild->name, target) == 0) { | ||||
|                     return grandchild; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return LookupId(node->parent, node, target); | ||||
| } | ||||
|  | @ -1,46 +0,0 @@ | |||
| /* Validates identifier usage in an AST. */ | ||||
| 
 | ||||
| #ifndef WRAITH_IDENTCHECK_H | ||||
| #define WRAITH_IDENTCHECK_H | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| #include "ast.h" | ||||
| 
 | ||||
| struct TypeTag; | ||||
| struct Node; | ||||
| 
 | ||||
| typedef enum NodeType { | ||||
|     Placeholder, | ||||
|     UnorderedScope, | ||||
|     OrderedScope, | ||||
|     Struct, | ||||
|     Function, | ||||
|     Variable | ||||
| } NodeType; | ||||
| 
 | ||||
| typedef struct IdNode { | ||||
|     NodeType type; | ||||
|     char *name; | ||||
|     struct TypeTag *typeTag; | ||||
|     struct IdNode *parent; | ||||
|     struct IdNode **children; | ||||
|     uint32_t childCount; | ||||
|     uint32_t childCapacity; | ||||
| } IdNode; | ||||
| 
 | ||||
| typedef struct IdStatus { | ||||
|     enum StatusCode { | ||||
|         Valid, | ||||
|     } StatusCode; | ||||
| } IdStatus; | ||||
| 
 | ||||
| 
 | ||||
| IdNode* MakeIdTree(struct Node *astNode, IdNode *parent); | ||||
| void PrintIdNode(IdNode *node); | ||||
| void PrintIdTree(IdNode *tree, uint32_t tabCount); | ||||
| int PrintAncestors(IdNode *node); | ||||
| IdNode* LookdownId(IdNode *root, NodeType targetType, char *targetName); | ||||
| IdNode* LookupId(IdNode *node, IdNode *prev, char* target); | ||||
| 
 | ||||
| #endif /* WRAITH_IDENTCHECK_H */ | ||||
							
								
								
									
										53
									
								
								src/main.c
								
								
								
								
							
							
						
						
									
										53
									
								
								src/main.c
								
								
								
								
							|  | @ -1,9 +1,9 @@ | |||
| #include <stdlib.h> | ||||
| #include "../lib/dropt/dropt.h" | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| #include "parser.h" | ||||
| #include "codegen.h" | ||||
| #include "identcheck.h" | ||||
| #include "parser.h" | ||||
| #include "validation.h" | ||||
| 
 | ||||
| int main(int argc, char *argv[]) | ||||
| { | ||||
|  | @ -14,10 +14,27 @@ int main(int argc, char *argv[]) | |||
|     int exitCode = EXIT_SUCCESS; | ||||
| 
 | ||||
|     dropt_option options[] = { | ||||
|         { 'h', "help", "Shows help.", NULL, dropt_handle_bool, &showHelp, dropt_attr_halt }, | ||||
|         { 'v', "parse-verbose", "Shows verbose parser output.", NULL, dropt_handle_bool, &parseVerbose }, | ||||
|         { 'O', "optimize", "Sets optimization level of the output IR. Must be a value between 0 and 3.", "number", dropt_handle_uint, &optimizationLevel }, | ||||
|         { 0 } /* Required sentinel value. */ | ||||
|         {'h', | ||||
|          "help", | ||||
|          "Shows help.", | ||||
|          NULL, | ||||
|          dropt_handle_bool, | ||||
|          &showHelp, | ||||
|          dropt_attr_halt}, | ||||
|         {'v', | ||||
|          "parse-verbose", | ||||
|          "Shows verbose parser output.", | ||||
|          NULL, | ||||
|          dropt_handle_bool, | ||||
|          &parseVerbose}, | ||||
|         {'O', | ||||
|          "optimize", | ||||
|          "Sets optimization level of the output IR. Must be a value between 0 " | ||||
|          "and 3.", | ||||
|          "number", | ||||
|          dropt_handle_uint, | ||||
|          &optimizationLevel}, | ||||
|         {0} /* Required sentinel value. */ | ||||
|     }; | ||||
| 
 | ||||
|     dropt_context *droptContext = dropt_new_context(options); | ||||
|  | @ -33,10 +50,13 @@ int main(int argc, char *argv[]) | |||
|     } | ||||
|     else | ||||
|     { | ||||
|         char** rest = dropt_parse(droptContext, -1, &argv[1]); | ||||
|         char **rest = dropt_parse(droptContext, -1, &argv[1]); | ||||
|         if (dropt_get_error(droptContext) != dropt_error_none) | ||||
|         { | ||||
|             fprintf(stderr, "wraith: %s\n", dropt_get_error_message(droptContext)); | ||||
|             fprintf( | ||||
|                 stderr, | ||||
|                 "wraith: %s\n", | ||||
|                 dropt_get_error_message(droptContext)); | ||||
|             exitCode = EXIT_FAILURE; | ||||
|         } | ||||
|         else if (showHelp) | ||||
|  | @ -65,12 +85,15 @@ int main(int argc, char *argv[]) | |||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     { | ||||
|                         IdNode *idTree = MakeIdTree(rootNode, NULL); | ||||
|                         PrintIdTree(idTree, /*tabCount=*/0); | ||||
|                         printf("\n"); | ||||
|                         PrintTree(rootNode, /*tabCount=*/0); | ||||
|                     } | ||||
|                     LinkParentPointers(rootNode, NULL); | ||||
|                     /* FIXME: ValidateIdentifiers should return some sort of
 | ||||
|                               error status object. */ | ||||
|                     ValidateIdentifiers(rootNode); | ||||
|                     TagIdentifierTypes(rootNode); | ||||
|                     ConvertCustomsToGenerics(rootNode); | ||||
|                     PrintNode(rootNode, 0); | ||||
| 
 | ||||
|                     printf("Beginning codegen.\n"); | ||||
|                     exitCode = Codegen(rootNode, optimizationLevel); | ||||
|                 } | ||||
|             } | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| #include <stdio.h> | ||||
| 
 | ||||
| #include "y.tab.h" | ||||
| #include "ast.h" | ||||
| #include "y.tab.h" | ||||
| 
 | ||||
| extern FILE *yyin; | ||||
| extern int yydebug; | ||||
|  | @ -31,7 +31,7 @@ int Parse(char *inputFilename, Node **pRootNode, uint8_t parseVerbose) | |||
|     { | ||||
|         if (parseVerbose) | ||||
|         { | ||||
|             PrintTree(*pRootNode, 0); | ||||
|             PrintNode(*pRootNode, 0); | ||||
|         } | ||||
|     } | ||||
|     else if (result == 1) | ||||
|  |  | |||
							
								
								
									
										44
									
								
								src/util.c
								
								
								
								
							
							
						
						
									
										44
									
								
								src/util.c
								
								
								
								
							|  | @ -1,16 +1,38 @@ | |||
| #include "util.h" | ||||
| 
 | ||||
| #include <string.h> | ||||
| #include <stdlib.h> | ||||
| 
 | ||||
| char* strdup (const char* s) | ||||
| char *strdup(const char *s) | ||||
| { | ||||
|   size_t slen = strlen(s); | ||||
|   char* result = malloc(slen + 1); | ||||
|   if(result == NULL) | ||||
|   { | ||||
|     return NULL; | ||||
|   } | ||||
|     size_t slen = strlen(s); | ||||
|     char *result = (char *)malloc(sizeof(char) * (slen + 1)); | ||||
|     if (result == NULL) | ||||
|     { | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|   memcpy(result, s, slen+1); | ||||
|   return result; | ||||
| } | ||||
|     memcpy(result, s, slen + 1); | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| char *w_strcat(char *s, char *s2) | ||||
| { | ||||
|     size_t slen = strlen(s); | ||||
|     size_t slen2 = strlen(s2); | ||||
|     s = realloc(s, sizeof(char) * (slen + slen2 + 1)); | ||||
|     strcat(s, s2); | ||||
|     return s; | ||||
| } | ||||
| 
 | ||||
| uint64_t str_hash(char *str) | ||||
| { | ||||
|     uint64_t hash = 5381; | ||||
|     size_t c; | ||||
| 
 | ||||
|     while ((c = *str++)) | ||||
|     { | ||||
|         hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ | ||||
|     } | ||||
| 
 | ||||
|     return hash; | ||||
| } | ||||
|  |  | |||
|  | @ -1,8 +1,11 @@ | |||
| #ifndef WRAITH_UTIL_H | ||||
| #define WRAITH_UTIL_H | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| #include <string.h> | ||||
| 
 | ||||
| char* strdup (const char* s); | ||||
| char *strdup(const char *s); | ||||
| char *w_strcat(char *s, char *s2); | ||||
| uint64_t str_hash(char *str); | ||||
| 
 | ||||
| #endif /* WRAITH_UTIL_H */ | ||||
|  |  | |||
|  | @ -0,0 +1,493 @@ | |||
| #include "validation.h" | ||||
| 
 | ||||
| #include <stdbool.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| 
 | ||||
| Node *GetIdFromStruct(Node *structDecl) | ||||
| { | ||||
|     if (structDecl->syntaxKind != StructDeclaration) | ||||
|     { | ||||
|         fprintf( | ||||
|             stderr, | ||||
|             "wraith: Attempted to call GetIdFromStruct on node with kind: " | ||||
|             "%s.\n", | ||||
|             SyntaxKindString(structDecl->syntaxKind)); | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     return structDecl->structDeclaration.identifier; | ||||
| } | ||||
| 
 | ||||
| Node *GetIdFromFunction(Node *funcDecl) | ||||
| { | ||||
|     if (funcDecl->syntaxKind != FunctionDeclaration) | ||||
|     { | ||||
|         fprintf( | ||||
|             stderr, | ||||
|             "wraith: Attempted to call GetIdFromFunction on node with kind: " | ||||
|             "%s.\n", | ||||
|             SyntaxKindString(funcDecl->syntaxKind)); | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     Node *sig = funcDecl->functionDeclaration.functionSignature; | ||||
|     return sig->functionSignature.identifier; | ||||
| } | ||||
| 
 | ||||
| Node *GetIdFromDeclaration(Node *decl) | ||||
| { | ||||
|     if (decl->syntaxKind != Declaration) | ||||
|     { | ||||
|         fprintf( | ||||
|             stderr, | ||||
|             "wraith: Attempted to call GetIdFromDeclaration on node with kind: " | ||||
|             "%s.\n", | ||||
|             SyntaxKindString(decl->syntaxKind)); | ||||
|     } | ||||
| 
 | ||||
|     return decl->declaration.identifier; | ||||
| } | ||||
| 
 | ||||
| bool AssignmentHasDeclaration(Node *assign) | ||||
| { | ||||
|     return ( | ||||
|         assign->syntaxKind == Assignment && | ||||
|         assign->assignmentStatement.left->syntaxKind == Declaration); | ||||
| } | ||||
| 
 | ||||
| Node *GetIdFromAssignment(Node *assign) | ||||
| { | ||||
|     if (assign->syntaxKind != Assignment) | ||||
|     { | ||||
|         fprintf( | ||||
|             stderr, | ||||
|             "wraith: Attempted to call GetIdFromAssignment on node with kind: " | ||||
|             "%s.\n", | ||||
|             SyntaxKindString(assign->syntaxKind)); | ||||
|     } | ||||
| 
 | ||||
|     if (AssignmentHasDeclaration(assign)) | ||||
|     { | ||||
|         return GetIdFromDeclaration(assign->assignmentStatement.left); | ||||
|     } | ||||
| 
 | ||||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
| bool NodeMayHaveId(Node *node) | ||||
| { | ||||
|     switch (node->syntaxKind) | ||||
|     { | ||||
|     case StructDeclaration: | ||||
|     case FunctionDeclaration: | ||||
|     case Declaration: | ||||
|     case Assignment: | ||||
|         return true; | ||||
|     default: | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| Node *TryGetId(Node *node) | ||||
| { | ||||
|     switch (node->syntaxKind) | ||||
|     { | ||||
|     case Assignment: | ||||
|         return GetIdFromAssignment(node); | ||||
|     case Declaration: | ||||
|         return GetIdFromDeclaration(node); | ||||
|     case FunctionDeclaration: | ||||
|         return GetIdFromFunction(node); | ||||
|     case StructDeclaration: | ||||
|         return GetIdFromStruct(node); | ||||
|     default: | ||||
|         return NULL; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| Node *LookupFunctionArgId(Node *funcDecl, char *target) | ||||
| { | ||||
|     Node *args = funcDecl->functionDeclaration.functionSignature | ||||
|                      ->functionSignature.arguments; | ||||
| 
 | ||||
|     uint32_t i; | ||||
|     for (i = 0; i < args->functionArgumentSequence.count; i += 1) | ||||
|     { | ||||
|         Node *arg = args->functionArgumentSequence.sequence[i]; | ||||
|         if (arg->syntaxKind != Declaration) | ||||
|         { | ||||
|             fprintf( | ||||
|                 stderr, | ||||
|                 "wraith: Encountered %s node in function signature args " | ||||
|                 "list.\n", | ||||
|                 SyntaxKindString(arg->syntaxKind)); | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         Node *argId = GetIdFromDeclaration(arg); | ||||
|         if (argId != NULL && strcmp(target, argId->identifier.name) == 0) | ||||
|             return argId; | ||||
|     } | ||||
| 
 | ||||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
| Node *LookupStructInternalId(Node *structDecl, char *target) | ||||
| { | ||||
|     Node *decls = structDecl->structDeclaration.declarationSequence; | ||||
| 
 | ||||
|     uint32_t i; | ||||
|     for (i = 0; i < decls->declarationSequence.count; i += 1) | ||||
|     { | ||||
|         Node *match = TryGetId(decls->declarationSequence.sequence[i]); | ||||
|         if (match != NULL && strcmp(target, match->identifier.name) == 0) | ||||
|             return match; | ||||
|     } | ||||
| 
 | ||||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
| Node *InspectNode(Node *node, char *target) | ||||
| { | ||||
|     /* If this node may have an identifier declaration inside it, attempt to
 | ||||
|      * look up the identifier | ||||
|      * node itself, returning it if it matches the given target name. */ | ||||
|     if (NodeMayHaveId(node)) | ||||
|     { | ||||
|         Node *candidateId = TryGetId(node); | ||||
|         if (candidateId != NULL && | ||||
|             strcmp(target, candidateId->identifier.name) == 0) | ||||
|             return candidateId; | ||||
|     } | ||||
| 
 | ||||
|     /* If the candidate node was not the one we wanted, but the node node is a
 | ||||
|      * function declaration, it's possible that the identifier we want is one of | ||||
|      * the function's parameters rather than the function's name itself. */ | ||||
|     if (node->syntaxKind == FunctionDeclaration) | ||||
|     { | ||||
|         Node *match = LookupFunctionArgId(node, target); | ||||
|         if (match != NULL) | ||||
|             return match; | ||||
|     } | ||||
| 
 | ||||
|     /* Likewise if the node node is a struct declaration, inspect the struct's
 | ||||
|      * internals | ||||
|      * to see if a top-level definition is the one we're looking for. */ | ||||
|     if (node->syntaxKind == StructDeclaration) | ||||
|     { | ||||
|         Node *match = LookupStructInternalId(node, target); | ||||
|         if (match != NULL) | ||||
|             return match; | ||||
|     } | ||||
| 
 | ||||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
| /* FIXME: Handle staged lookups for AccessExpressions. */ | ||||
| /* FIXME: Similar to above, disallow inspection of struct internals outside of
 | ||||
|  *        AccessExpressions. */ | ||||
| Node *LookupId(Node *current, Node *prev, char *target) | ||||
| { | ||||
|     if (current == NULL) | ||||
|         return NULL; | ||||
| 
 | ||||
|     Node *match; | ||||
| 
 | ||||
|     /* First inspect the current node to see if it contains the target
 | ||||
|      * identifier. */ | ||||
|     match = InspectNode(current, target); | ||||
|     if (match != NULL) | ||||
|         return match; | ||||
| 
 | ||||
|     /* If this is the start of our search, we should not attempt to look at
 | ||||
|      * child nodes. Only looking up the AST is valid at this point. | ||||
|      * | ||||
|      * This has the notable side-effect that this function will return NULL if | ||||
|      * you attempt to look up a struct's internals starting from the node | ||||
|      * representing the struct itself. The same is true for functions. */ | ||||
|     if (prev == NULL) | ||||
|         return LookupId(current->parent, current, target); | ||||
| 
 | ||||
|     uint32_t i; | ||||
|     uint32_t idxLimit; | ||||
|     switch (current->syntaxKind) | ||||
|     { | ||||
|     case DeclarationSequence: | ||||
|         for (i = 0; i < current->declarationSequence.count; i += 1) | ||||
|         { | ||||
|             Node *decl = current->declarationSequence.sequence[i]; | ||||
|             match = InspectNode(decl, target); | ||||
|             if (match != NULL) | ||||
|                 return match; | ||||
|         } | ||||
|         break; | ||||
|     case StatementSequence: | ||||
|         idxLimit = current->statementSequence.count; | ||||
|         for (i = 0; i < current->statementSequence.count; i += 1) | ||||
|         { | ||||
|             if (current->statementSequence.sequence[i] == prev) | ||||
|             { | ||||
|                 idxLimit = i; | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         for (i = 0; i < idxLimit; i += 1) | ||||
|         { | ||||
|             Node *stmt = current->statementSequence.sequence[i]; | ||||
|             if (stmt == prev) | ||||
|                 break; | ||||
| 
 | ||||
|             match = InspectNode(stmt, target); | ||||
|             if (match != NULL) | ||||
|                 return match; | ||||
|         } | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     return LookupId(current->parent, current, target); | ||||
| } | ||||
| 
 | ||||
| /* FIXME: This function should be extended to handle multi-stage ID lookups for
 | ||||
|  *        AccessExpression nodes. */ | ||||
| /* FIXME: Make this function return an error status object of some kind.
 | ||||
|  *        A non-OK status should halt compilation. */ | ||||
| void ValidateIdentifiers(Node *node) | ||||
| { | ||||
|     if (node == NULL) | ||||
|         return; | ||||
| 
 | ||||
|     /* Skip over generic arguments. They contain Identifiers but are not
 | ||||
|      * actually identifiers, they declare types. */ | ||||
|     if (node->syntaxKind == GenericDeclarations) | ||||
|         return; | ||||
| 
 | ||||
|     if (node->syntaxKind != Identifier) | ||||
|     { | ||||
|         Recurse(node, *ValidateIdentifiers); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     char *name = node->identifier.name; | ||||
|     Node *decl = LookupId(node, NULL, name); | ||||
|     if (decl == NULL) | ||||
|     { | ||||
|         /* FIXME: Express this case as an error with AST information, see the
 | ||||
|          *        FIXME comment above. */ | ||||
|         fprintf( | ||||
|             stderr, | ||||
|             "wraith: Could not find definition of identifier %s.\n", | ||||
|             name); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /* FIXME: This function should be extended to handle multi-stage ID lookups for
 | ||||
|  *        AccessExpression nodes. */ | ||||
| void TagIdentifierTypes(Node *node) | ||||
| { | ||||
|     if (node == NULL) | ||||
|         return; | ||||
| 
 | ||||
|     switch (node->syntaxKind) | ||||
|     { | ||||
|     case AllocExpression: | ||||
|         node->typeTag = MakeTypeTag(node); | ||||
|         break; | ||||
| 
 | ||||
|     case Declaration: | ||||
|         node->declaration.identifier->typeTag = MakeTypeTag(node); | ||||
|         break; | ||||
| 
 | ||||
|     case FunctionDeclaration: | ||||
|         node->functionDeclaration.functionSignature->functionSignature | ||||
|             .identifier->typeTag = MakeTypeTag(node); | ||||
|         break; | ||||
| 
 | ||||
|     case StructDeclaration: | ||||
|         node->structDeclaration.identifier->typeTag = MakeTypeTag(node); | ||||
|         break; | ||||
| 
 | ||||
|     case GenericDeclaration: | ||||
|         node->genericDeclaration.identifier->typeTag = MakeTypeTag(node); | ||||
|         break; | ||||
| 
 | ||||
|     case Type: | ||||
|         node->typeTag = MakeTypeTag(node); | ||||
|         break; | ||||
| 
 | ||||
|     case Identifier: | ||||
|     { | ||||
|         if (node->typeTag != NULL) | ||||
|             return; | ||||
| 
 | ||||
|         char *name = node->identifier.name; | ||||
|         Node *declaration = LookupId(node, NULL, name); | ||||
|         /* FIXME: Remove this case once ValidateIdentifiers returns error status
 | ||||
|          * info and halts compilation. See ValidateIdentifiers FIXME. */ | ||||
|         if (declaration == NULL) | ||||
|         { | ||||
|             TypeTag *tag = (TypeTag *)malloc(sizeof(TypeTag)); | ||||
|             tag->type = Unknown; | ||||
|             node->typeTag = tag; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             node->typeTag = declaration->typeTag; | ||||
|         } | ||||
|         break; | ||||
|     } | ||||
|     } | ||||
| 
 | ||||
|     Recurse(node, *TagIdentifierTypes); | ||||
| } | ||||
| 
 | ||||
| Node *LookupType(Node *current, char *target) | ||||
| { | ||||
|     if (current == NULL) | ||||
|         return NULL; | ||||
| 
 | ||||
|     switch (current->syntaxKind) | ||||
|     { | ||||
|     /* If we've encountered a function declaration, check to see if it's generic
 | ||||
|      * and, if so, if one of its type parameters is the target. */ | ||||
|     case FunctionDeclaration: | ||||
|     { | ||||
|         Node *typeArgs = current->functionDeclaration.functionSignature | ||||
|                              ->functionSignature.genericDeclarations; | ||||
|         uint32_t i; | ||||
|         for (i = 0; i < typeArgs->genericDeclarations.count; i += 1) | ||||
|         { | ||||
|             Node *arg = typeArgs->genericDeclarations.declarations[i]; | ||||
|             Node *argId = arg->genericDeclaration.identifier; | ||||
|             char *argName = argId->identifier.name; | ||||
|             /* note: return the GenericDeclaration, not the Identifier, so that
 | ||||
|              * the caller can differentiate between generics and customs. */ | ||||
|             if (strcmp(target, argName) == 0) | ||||
|             { | ||||
|                 return arg; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return LookupType(current->parent, target); | ||||
|     } | ||||
| 
 | ||||
|     case StructDeclaration: | ||||
|     { | ||||
|         uint32_t i; | ||||
|         Node *typeArgs = current->structDeclaration.genericDeclarations; | ||||
|         for (i = 0; i < typeArgs->genericDeclarations.count; i += 1) | ||||
|         { | ||||
|             Node *arg = typeArgs->genericDeclarations.declarations[i]; | ||||
|             Node *argId = arg->genericDeclaration.identifier; | ||||
|             char *argName = argId->identifier.name; | ||||
|             /* note: return the GenericDeclaration, not the Identifier, so that
 | ||||
|              * the caller can differentiate between generics and customs. */ | ||||
|             if (strcmp(target, argName) == 0) | ||||
|             { | ||||
|                 return arg; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         Node *structId = GetIdFromStruct(current); | ||||
|         if (strcmp(target, structId->identifier.name) == 0) | ||||
|         { | ||||
|             return structId; | ||||
|         } | ||||
| 
 | ||||
|         return LookupType(current->parent, target); | ||||
|     } | ||||
| 
 | ||||
|     /* If we encounter a declaration sequence, search each of its children for
 | ||||
|      * struct definitions in case one of them is the target. */ | ||||
|     case DeclarationSequence: | ||||
|     { | ||||
|         uint32_t i; | ||||
|         for (i = 0; i < current->declarationSequence.count; i += 1) | ||||
|         { | ||||
|             Node *decl = current->declarationSequence.sequence[i]; | ||||
|             if (decl->syntaxKind == StructDeclaration) | ||||
|             { | ||||
|                 Node *structId = GetIdFromStruct(decl); | ||||
|                 if (strcmp(target, structId->identifier.name) == 0) | ||||
|                     return structId; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return LookupType(current->parent, target); | ||||
|     } | ||||
| 
 | ||||
|     default: | ||||
|         return LookupType(current->parent, target); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /* FIXME: This function should be modified to handle type parameters over
 | ||||
|  * structs. */ | ||||
| void ConvertCustomsToGenerics(Node *node) | ||||
| { | ||||
|     if (node == NULL) | ||||
|         return; | ||||
| 
 | ||||
|     switch (node->syntaxKind) | ||||
|     { | ||||
|     case Declaration: | ||||
|     { | ||||
|         Node *id = node->declaration.identifier; | ||||
|         Node *type = node->declaration.type->type.typeNode; | ||||
|         if (type->syntaxKind == CustomTypeNode) | ||||
|         { | ||||
|             char *target = id->typeTag->value.customType; | ||||
|             Node *typeLookup = LookupType(node, target); | ||||
|             if (typeLookup != NULL && | ||||
|                 typeLookup->syntaxKind == GenericDeclaration) | ||||
|             { | ||||
|                 id->typeTag->type = Generic; | ||||
|                 free(node->declaration.type); | ||||
|                 node->declaration.type = | ||||
|                     MakeGenericTypeNode(id->typeTag->value.genericType); | ||||
|             } | ||||
|         } | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     case FunctionSignature: | ||||
|     { | ||||
|         Node *id = node->functionSignature.identifier; | ||||
|         Node *type = node->functionSignature.type->type.typeNode; | ||||
|         if (type->syntaxKind == CustomTypeNode) | ||||
|         { | ||||
|             char *target = id->typeTag->value.customType; | ||||
|             Node *typeLookup = LookupType(node, target); | ||||
|             if (typeLookup != NULL && | ||||
|                 typeLookup->syntaxKind == GenericDeclaration) | ||||
|             { | ||||
|                 id->typeTag->type = Generic; | ||||
|                 free(node->functionSignature.type); | ||||
|                 node->functionSignature.type = | ||||
|                     MakeGenericTypeNode(id->typeTag->value.genericType); | ||||
|             } | ||||
|         } | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     case GenericArgument: | ||||
|     { | ||||
|         Node *typeNode = node->genericArgument.type; | ||||
|         if (typeNode->typeTag->type == Custom) | ||||
|         { | ||||
|             char *target = typeNode->typeTag->value.customType; | ||||
|             Node *typeLookup = LookupType(node, target); | ||||
|             if (typeLookup != NULL && | ||||
|                 typeLookup->syntaxKind == GenericDeclaration) | ||||
|             { | ||||
|                 typeNode->typeTag->type = Generic; | ||||
|             } | ||||
|         } | ||||
|         break; | ||||
|     } | ||||
|     } | ||||
| 
 | ||||
|     Recurse(node, *ConvertCustomsToGenerics); | ||||
| } | ||||
|  | @ -0,0 +1,10 @@ | |||
| #ifndef WRAITH_VALIDATION_H | ||||
| #define WRAITH_VALIDATION_H | ||||
| 
 | ||||
| #include "ast.h" | ||||
| 
 | ||||
| void ValidateIdentifiers(Node *node); | ||||
| void TagIdentifierTypes(Node *node); | ||||
| void ConvertCustomsToGenerics(Node *node); | ||||
| 
 | ||||
| #endif /* WRAITH_VALIDATION_H */ | ||||
		Loading…
	
		Reference in New Issue