diff options
| author | nasr <nsrddyn@gmail.com> | 2026-03-26 22:35:30 +0100 |
|---|---|---|
| committer | nasr <nsrddyn@gmail.com> | 2026-04-13 17:24:42 +0200 |
| commit | dd5586abec207dd4acd16d51ce0d392c03e5e957 (patch) | |
| tree | e56573f49ebb2a3236a39148842dc80bde5a286d /source/fajr_parser/fajr_parser.c | |
feature(main): initmain
feature(main): init
Diffstat (limited to 'source/fajr_parser/fajr_parser.c')
| -rw-r--r-- | source/fajr_parser/fajr_parser.c | 364 |
1 files changed, 364 insertions, 0 deletions
diff --git a/source/fajr_parser/fajr_parser.c b/source/fajr_parser/fajr_parser.c new file mode 100644 index 0000000..cfd1fb2 --- /dev/null +++ b/source/fajr_parser/fajr_parser.c | |||
| @@ -0,0 +1,364 @@ | |||
| 1 | internal syntax_node * | ||
| 2 | PeekToOffset(syntax_node *Node, i32 PeekOffset, b32 findChild) | ||
| 3 | { | ||
| 4 | if(PeekOffset < 0) | ||
| 5 | { | ||
| 6 | for(i32 PeekCount = 0; PeekCount < PeekOffset; PeekCount++) | ||
| 7 | { | ||
| 8 | if(!Node || !Node->Next) return &nil_syntax_node; | ||
| 9 | Node = Node->Next; | ||
| 10 | } | ||
| 11 | } | ||
| 12 | else if(PeekOffset > 0) | ||
| 13 | { | ||
| 14 | for(i32 PeekCount = 0; PeekCount < PeekOffset; PeekCount++) | ||
| 15 | { | ||
| 16 | if(!Node || !Node->First) return &nil_syntax_node; | ||
| 17 | Node = Node->First; | ||
| 18 | } | ||
| 19 | } | ||
| 20 | else if(PeekOffset == 0) | ||
| 21 | { | ||
| 22 | return Node; | ||
| 23 | } | ||
| 24 | |||
| 25 | return &nil_syntax_node; | ||
| 26 | } | ||
| 27 | |||
| 28 | internal void | ||
| 29 | NodePushChild(concrete_syntax_tree *Tree, syntax_node *Node) | ||
| 30 | { | ||
| 31 | Node->Parent = Tree->Current; | ||
| 32 | |||
| 33 | if(Tree->Current->First == &nil_syntax_node) | ||
| 34 | { | ||
| 35 | Tree->Current->First = Node; | ||
| 36 | Tree->Current->Last = Node; | ||
| 37 | } | ||
| 38 | else | ||
| 39 | { | ||
| 40 | Tree->Current->Last->Next = Node; | ||
| 41 | Tree->Current->Last = Node; | ||
| 42 | } | ||
| 43 | } | ||
| 44 | |||
| 45 | internal void | ||
| 46 | NodePushNext(concrete_syntax_tree *Tree, syntax_node *Node) | ||
| 47 | { | ||
| 48 | Node->Parent = Tree->Current; | ||
| 49 | |||
| 50 | if(Tree->Current->Next == &nil_syntax_node) Tree->Current->Next = Node; | ||
| 51 | else Tree->Current->Last->Next = Node; | ||
| 52 | } | ||
| 53 | |||
| 54 | internal inline b32 | ||
| 55 | IsNilSyntaxNode(syntax_node *Node) | ||
| 56 | { | ||
| 57 | return Node == &nil_syntax_node || Node == NULL; | ||
| 58 | } | ||
| 59 | |||
| 60 | internal void | ||
| 61 | DisownNode(concrete_syntax_tree *Tree, syntax_node *Node) | ||
| 62 | { | ||
| 63 | Node->First = &nil_syntax_node; | ||
| 64 | Node->Last = &nil_syntax_node; | ||
| 65 | Node->Parent = &nil_syntax_node; | ||
| 66 | Node->Next = &nil_syntax_node; | ||
| 67 | Node->Token = &nil_token; | ||
| 68 | Node->Type = SyntaxNodeUnwanted; | ||
| 69 | } | ||
| 70 | |||
| 71 | internal void | ||
| 72 | CopyNode(syntax_node *Dest, syntax_node *Src) | ||
| 73 | { | ||
| 74 | Src->First = Dest->First; | ||
| 75 | Src->Parent = Dest->Parent; | ||
| 76 | Src->Last = Dest->Last; | ||
| 77 | Src->Next = Dest->Next; | ||
| 78 | Src->Token = Dest->Token; | ||
| 79 | Src->Type = Dest->Type; | ||
| 80 | } | ||
| 81 | |||
| 82 | /* Insert the node at any given spot thus hopefully allowwing for code changes without breaking */ | ||
| 83 | internal void | ||
| 84 | AdoptNode(concrete_syntax_tree *Tree, syntax_node *Node, syntax_node *ParentNode, b32 asChild) | ||
| 85 | { | ||
| 86 | // | ||
| 87 | if (!IsNilSyntaxNode(ParentNode)) return; | ||
| 88 | |||
| 89 | // | ||
| 90 | if (asChild) | ||
| 91 | { | ||
| 92 | ParentNode->Last->Next = Node; | ||
| 93 | Node->Next = ParentNode->Last; | ||
| 94 | } | ||
| 95 | else | ||
| 96 | { | ||
| 97 | // copy node | ||
| 98 | ParentNode->Next = Node; | ||
| 99 | CopyNode(Node, ParentNode->Next); | ||
| 100 | } | ||
| 101 | |||
| 102 | |||
| 103 | NodePushNext(Tree, Node); | ||
| 104 | |||
| 105 | return; | ||
| 106 | } | ||
| 107 | |||
| 108 | |||
| 109 | internal inline void | ||
| 110 | Ground(token *Token) | ||
| 111 | { | ||
| 112 | Token->Flags = (token_flags)(Token->Flags | FlagDirty); | ||
| 113 | } | ||
| 114 | |||
| 115 | internal concrete_syntax_tree * | ||
| 116 | Parse(mem_arena *Arena, token_list *List, concrete_syntax_tree *Tree) | ||
| 117 | { | ||
| 118 | for(token_node *TokenNode = List->Root; | ||
| 119 | TokenNode != &nil_token_node && TokenNode != NULL; | ||
| 120 | TokenNode = TokenNode->Next) | ||
| 121 | { | ||
| 122 | token *Token = TokenNode->Token; | ||
| 123 | syntax_node *SyntaxNode; | ||
| 124 | |||
| 125 | { | ||
| 126 | SyntaxNode = PushStruct(Arena, syntax_node); | ||
| 127 | SyntaxNode->Token = Token; | ||
| 128 | SyntaxNode->First = &nil_syntax_node; | ||
| 129 | SyntaxNode->Last = &nil_syntax_node; | ||
| 130 | SyntaxNode->Next = &nil_syntax_node; | ||
| 131 | SyntaxNode->Parent = &nil_syntax_node; | ||
| 132 | } | ||
| 133 | |||
| 134 | |||
| 135 | if(IsNilSyntaxNode(Tree->Root)) | ||
| 136 | { | ||
| 137 | Tree->Root = SyntaxNode; | ||
| 138 | Tree->Current = SyntaxNode; | ||
| 139 | } | ||
| 140 | |||
| 141 | switch((token_type)Token->Type) | ||
| 142 | { | ||
| 143 | case TokenIdentifier: | ||
| 144 | { | ||
| 145 | if(!IsNilTokenNode(TokenNode) && TokenNode->Next->Token->Type == (token_type)'=') | ||
| 146 | { | ||
| 147 | token_node *ValueNode = TokenNode->Next->Next; | ||
| 148 | |||
| 149 | if(ValueNode->Token->Type != TokenIdentifierAssignmentValue && | ||
| 150 | ValueNode->Token->Type != TokenValue) | ||
| 151 | { | ||
| 152 | ValueNode->Token->Type = TokenIdentifierAssignmentValue; | ||
| 153 | } | ||
| 154 | } | ||
| 155 | |||
| 156 | if(Tree->Current != SyntaxNode) | ||
| 157 | { | ||
| 158 | NodePushChild(Tree, SyntaxNode); | ||
| 159 | } | ||
| 160 | } | ||
| 161 | break; | ||
| 162 | |||
| 163 | case TokenIdentifierAssignmentValue: | ||
| 164 | { | ||
| 165 | NodePushChild(Tree, SyntaxNode); | ||
| 166 | } | ||
| 167 | break; | ||
| 168 | |||
| 169 | case TokenNumber: | ||
| 170 | case TokenString: | ||
| 171 | { | ||
| 172 | if(Tree->Current && Tree->Current->Token->Type == (token_type)'=') | ||
| 173 | { | ||
| 174 | Token->Type = TokenIdentifierAssignmentValue; | ||
| 175 | |||
| 176 | if(Tree->Current->Parent && Tree->Current->Parent->Token->Type != TokenIdentifier) | ||
| 177 | { | ||
| 178 | Ground(Token); | ||
| 179 | } | ||
| 180 | } | ||
| 181 | |||
| 182 | NodePushChild(Tree, SyntaxNode); | ||
| 183 | } | ||
| 184 | break; | ||
| 185 | |||
| 186 | case TokenDoubleEqual: | ||
| 187 | { | ||
| 188 | NodePushChild(Tree, SyntaxNode); | ||
| 189 | |||
| 190 | if(!IsNilSyntaxNode(Tree->Current->Parent)) | ||
| 191 | { | ||
| 192 | Tree->Current->First = Tree->Current->Parent; | ||
| 193 | Tree->Current->Last = Tree->Current->Next; | ||
| 194 | Tree->Current->Parent = Tree->Current; | ||
| 195 | } | ||
| 196 | } | ||
| 197 | break; | ||
| 198 | |||
| 199 | case TokenGreaterEqual: | ||
| 200 | case TokenLesserEqual: | ||
| 201 | case(token_type)'<': | ||
| 202 | case(token_type)'>': | ||
| 203 | { | ||
| 204 | NodePushChild(Tree, SyntaxNode); | ||
| 205 | Tree->Current = SyntaxNode; | ||
| 206 | } | ||
| 207 | break; | ||
| 208 | |||
| 209 | case(token_type)'(': | ||
| 210 | { | ||
| 211 | syntax_node *Current = Tree->Current; | ||
| 212 | Tree->Current->First = PeekToOffset(Tree->Current, 1, 0); | ||
| 213 | |||
| 214 | while(Tree->Current->Token->Type != (token_type)')' && !IsNilSyntaxNode(Tree->Current->Next)) | ||
| 215 | { | ||
| 216 | Current = Current->Next; | ||
| 217 | } | ||
| 218 | if(Current == &nil_syntax_node) | ||
| 219 | { | ||
| 220 | print("Forgot to close paran"); | ||
| 221 | } | ||
| 222 | } | ||
| 223 | break; | ||
| 224 | |||
| 225 | case(token_type)')': | ||
| 226 | { | ||
| 227 | while(Tree->Current && | ||
| 228 | Tree->Current != &nil_syntax_node && | ||
| 229 | Tree->Current->Token->Type != (token_type)'(') | ||
| 230 | { | ||
| 231 | Tree->Current = Tree->Current->Parent; | ||
| 232 | } | ||
| 233 | |||
| 234 | if(Tree->Current && Tree->Current->Parent) | ||
| 235 | { | ||
| 236 | Tree->Current = Tree->Current->Parent; | ||
| 237 | } | ||
| 238 | } | ||
| 239 | break; | ||
| 240 | |||
| 241 | case(token_type)'{': | ||
| 242 | { | ||
| 243 | syntax_node *Node = &nil_syntax_node; | ||
| 244 | |||
| 245 | for(i32 index = 0; PeekToOffset(Tree->Current, index, 0); ++index) | ||
| 246 | { | ||
| 247 | Tree->Current->First = Tree->Current->Next; | ||
| 248 | // TODO(nasr): was doing something here | ||
| 249 | } | ||
| 250 | } | ||
| 251 | break; | ||
| 252 | |||
| 253 | case(token_type)'}': | ||
| 254 | { | ||
| 255 | if(Tree->Current && Tree->Current->Parent) | ||
| 256 | { | ||
| 257 | Tree->Current = Tree->Current->Parent; | ||
| 258 | } | ||
| 259 | } | ||
| 260 | break; | ||
| 261 | |||
| 262 | case(token_type)';': | ||
| 263 | { | ||
| 264 | Tree->Current->Last = Tree->Current; | ||
| 265 | Tree->Current = Tree->Current->Parent; | ||
| 266 | } | ||
| 267 | break; | ||
| 268 | |||
| 269 | case TokenFunc: | ||
| 270 | { | ||
| 271 | // TODO(nasr): define the function body | ||
| 272 | NodePushChild(Tree, SyntaxNode); | ||
| 273 | Tree->Current = SyntaxNode; | ||
| 274 | } | ||
| 275 | break; | ||
| 276 | |||
| 277 | case TokenReturn: | ||
| 278 | { | ||
| 279 | if(Tree->Current && | ||
| 280 | Tree->Current->Parent && | ||
| 281 | Tree->Current->Parent->Token->Type != TokenFunc) | ||
| 282 | { | ||
| 283 | Ground(Token); | ||
| 284 | } | ||
| 285 | |||
| 286 | NodePushChild(Tree, SyntaxNode); | ||
| 287 | Tree->Current = SyntaxNode; | ||
| 288 | } | ||
| 289 | break; | ||
| 290 | |||
| 291 | case TokenIf: | ||
| 292 | { | ||
| 293 | NodePushChild(Tree, SyntaxNode); | ||
| 294 | Tree->Current = SyntaxNode; | ||
| 295 | } | ||
| 296 | break; | ||
| 297 | |||
| 298 | case TokenElse: | ||
| 299 | { | ||
| 300 | // TODO(nasr): handle no body | ||
| 301 | NodePushChild(Tree, SyntaxNode); | ||
| 302 | } | ||
| 303 | break; | ||
| 304 | |||
| 305 | case TokenWhile: | ||
| 306 | case TokenFor: | ||
| 307 | { | ||
| 308 | NodePushChild(Tree, SyntaxNode); | ||
| 309 | Tree->Current = SyntaxNode; | ||
| 310 | } | ||
| 311 | break; | ||
| 312 | |||
| 313 | case TokenBreak: | ||
| 314 | { | ||
| 315 | token_type Type = Tree->Current->Parent->Token->Type; | ||
| 316 | |||
| 317 | if(Type != TokenFor && Type != TokenWhile) | ||
| 318 | { | ||
| 319 | Ground(Token); | ||
| 320 | print("Break statement not allowed here"); | ||
| 321 | } | ||
| 322 | NodePushChild(Tree, SyntaxNode); | ||
| 323 | } | ||
| 324 | break; | ||
| 325 | |||
| 326 | case TokenContinue: | ||
| 327 | { | ||
| 328 | NodePushChild(Tree, SyntaxNode); | ||
| 329 | } | ||
| 330 | break; | ||
| 331 | |||
| 332 | case TokenExpression: | ||
| 333 | case TokenParam: | ||
| 334 | { | ||
| 335 | NodePushChild(Tree, SyntaxNode); | ||
| 336 | Tree->Current = SyntaxNode; | ||
| 337 | } | ||
| 338 | break; | ||
| 339 | |||
| 340 | case TokenStar: | ||
| 341 | { | ||
| 342 | // TODO(nasr): once we get to better visualizations i think | ||
| 343 | NodePushChild(Tree, SyntaxNode); | ||
| 344 | } | ||
| 345 | break; | ||
| 346 | |||
| 347 | case TokenUndefined: | ||
| 348 | { | ||
| 349 | Ground(Token); | ||
| 350 | NodePushChild(Tree, SyntaxNode); | ||
| 351 | } | ||
| 352 | break; | ||
| 353 | |||
| 354 | default: | ||
| 355 | { | ||
| 356 | Ground(Token); | ||
| 357 | NodePushChild(Tree, SyntaxNode); | ||
| 358 | } | ||
| 359 | break; | ||
| 360 | } | ||
| 361 | } | ||
| 362 | |||
| 363 | return Tree; | ||
| 364 | } | ||
