module: parser rcs-header: $Header: /scm/cvs/src/d2c/compiler/parser/parser.input,v 1.8 2003/03/03 14:18:03 gabor Exp $ copyright: see below %% ;;;; Program structure :entry-point source-record :entry-point expression :entry-point variable :entry-point bindings :entry-point body-opt :entry-point case-body-opt :entry-point property-list-opt :entry-point parameter-list-opt :entry-point variable-list-opt :entry-point macro-call :token EOF :token ERROR :token LEFT-PAREN :token RIGHT-PAREN :token COMMA :token DOT :token SEMICOLON :token LEFT-BRACKET :token RIGHT-BRACKET :token LEFT-BRACE :token RIGHT-BRACE :token DOUBLE-COLON :token MINUS :token EQUAL :token DOUBLE-EQUAL :token ARROW :token SHARP-PAREN :token SHARP-BRACKET :token DOUBLE-SHARP :token QUESTION :token DOUBLE-QUESTION :token QUESTION-EQUAL :token ELLIPSIS :token TRUE :token FALSE :token NEXT :token REST :token KEY :token ALL-KEYS :token INCLUDE :token DEFINE :token END :token HANDLER :token LET :token LOCAL :token MACRO :token OTHERWISE :token RAW-ORDINARY-WORD :token RAW-BEGIN-WORD :token RAW-FUNCTION-WORD :token ORDINARY-DEFINE-BODY-WORD :token BEGIN-AND-DEFINE-BODY-WORD :token FUNCTION-AND-DEFINE-BODY-WORD :token ORDINARY-DEFINE-LIST-WORD :token BEGIN-AND-DEFINE-LIST-WORD :token FUNCTION-AND-DEFINE-LIST-WORD :token QUOTED-NAME :token CONSTRAINED-NAME :token TILDE :token OTHER-BINARY-OPERATOR :token LITERAL :token STRING :token SYMBOL :token PARSED-DEFINITION-MACRO-CALL :token PARSED-SPECIAL-DEFINITION :token PARSED-LOCAL-DECLARATION :token PARSED-EXPRESSION :token PARSED-CONSTANT :token PARSED-MACRO-CALL :token PARSED-PARAMETER-LIST :token PARSED-VARIABLE-LIST :token FEATURE-IF :token FEATURE-ELSEIF :token FEATURE-ELSE :token FEATURE-ENDIF :union SHARP-WORD (TRUE FALSE NEXT REST KEY ALL-KEYS INCLUDE) :union BEGIN-WORD (RAW-BEGIN-WORD BEGIN-AND-DEFINE-BODY-WORD BEGIN-AND-DEFINE-LIST-WORD) :union FUNCTION-WORD (RAW-FUNCTION-WORD FUNCTION-AND-DEFINE-BODY-WORD FUNCTION-AND-DEFINE-LIST-WORD) :union DEFINE-BODY-WORD (ORDINARY-DEFINE-BODY-WORD BEGIN-AND-DEFINE-BODY-WORD FUNCTION-AND-DEFINE-BODY-WORD) :union DEFINE-LIST-WORD (ORDINARY-DEFINE-LIST-WORD BEGIN-AND-DEFINE-LIST-WORD FUNCTION-AND-DEFINE-LIST-WORD) :union MACRO-NAME (ORDINARY-NAME FUNCTION-WORD BEGIN-WORD) :union NAME-NOT-END (MACRO-NAME DEFINE HANDLER LET LOCAL MACRO OTHERWISE) :union NAME (NAME-NOT-END END) :union UNRESERVED-NAME (RAW-ORDINARY-WORD QUOTED-NAME) :union ORDINARY-NAME (UNRESERVED-NAME ORDINARY-DEFINE-BODY-WORD ORDINARY-DEFINE-LIST-WORD) :union MACRO-NAME-NOT-DEFINE-BODY-WORD (UNRESERVED-NAME RAW-BEGIN-WORD RAW-FUNCTION-WORD DEFINE-LIST-WORD) :union BINARY-OPERATOR (MINUS EQUAL DOUBLE-EQUAL OTHER-BINARY-OPERATOR) :union UNARY-OPERATOR (MINUS TILDE) :union OPERATOR (BINARY-OPERATOR UNARY-OPERATOR) ;;;; Program Structure :type source-record source-record () #f; % source-record (top-level-forms) #f; % source-record (top-level-forms SEMICOLON) #f; % source-record (top-level-body) #f; % source-record (top-level-body-semi) #f; % source-record (top-level-forms SEMICOLON top-level-body) #f; % source-record (top-level-forms SEMICOLON top-level-body-semi) #f; % ; Top-level-forms is just like body, except that it calls ; process-top-level-form on each form instead of collecting them ; into a body. :type top-level-forms top-level-forms (top-level-form) #f; % top-level-forms (top-level-forms SEMICOLON top-level-form) #f; % :type top-level-form top-level-form (definition) process-top-level-form(%1); #f; % top-level-form (expression) process-top-level-form(%1); #f; % :type top-level-body top-level-body (top-level-body-aux) process-top-level-form(make-body(%1, @1)); #f; % :type top-level-body-semi top-level-body-semi (top-level-body-aux-semi) process-top-level-form(make-body(%1, @1)); #f; % :type top-level-body-aux top-level-body-aux (local-declaration) stretchy-vector(%1); % top-level-body-aux (top-level-body-aux-semi constituent) add!(%1, %2); % :type top-level-body-aux-semi top-level-body-aux-semi (top-level-body-aux SEMICOLON) %1; % :type body-opt body-opt () make(, source-location: simplify-source-location(@0), parts: #[]); % body-opt (body) make-body(%1, @1); % :type body body (constituents) %1; % body (constituents SEMICOLON) %1; % :type constituents constituents (constituent) stretchy-vector(%1); % constituents (constituents SEMICOLON constituent) add!(%1, %3); % :type constituent constituent (definition) %1; % constituent (local-declaration) %1; % constituent (expression) %1; % :type macro-call macro-call (definition-macro-call) %1; % macro-call (statement) %1; % macro-call (function-macro-call) %1; % macro-call (PARSED-MACRO-CALL) %1.token-parse-tree; % ;; Property lists :type property-list-opt property-list-opt () #[]; % property-list-opt (property-list) as(, %1); % :type property-list property-list (SYMBOL basic-fragment) stretchy-vector(make(, keyword: %1, value: %2)); % property-list (property-list COMMA SYMBOL basic-fragment) add!(%1, make(, comma: %2, comma-srcloc: @2, keyword: %3, keyword-srcloc: @3, value: %4)); % ;;;; Fragments. :type body-fragment-opt body-fragment-opt () make(, source-location: @0); % body-fragment-opt (body-fragment) %1; % :type body-fragment body-fragment (non-statement-body-fragment) %1; % body-fragment (statement non-statement-body-fragment) append-fragments!(make-parsed-fragment(%1, source-location: @1), %2); % body-fragment (statement) make-parsed-fragment(%1, source-location: @1); % :type list-fragment-opt list-fragment-opt () make(, source-location: @0); % list-fragment-opt (list-fragment) %1; % :type list-fragment list-fragment (non-statement-list-fragment) %1; % list-fragment (statement non-statement-list-fragment) append-fragments!(make-parsed-fragment(%1, source-location: @1), %2); % list-fragment (statement) make-parsed-fragment(%1, source-location: @1); % :type basic-fragment-opt basic-fragment-opt () make(, source-location: @0); % basic-fragment-opt (basic-fragment) %1; % :type basic-fragment basic-fragment (non-statement-basic-fragment) %1; % basic-fragment (statement non-statement-basic-fragment) append-fragments!(make-parsed-fragment(%1, source-location: @1), %2); % basic-fragment (statement) make-parsed-fragment(%1, source-location: @1); % :type non-statement-body-fragment non-statement-body-fragment (definition semicolon-fragment-opt) append-fragments!(make-parsed-fragment(%1, source-location: @1), %2); % non-statement-body-fragment (local-declaration semicolon-fragment-opt) append-fragments!(make-parsed-fragment(%1, source-location: @1), %2); % non-statement-body-fragment (simple-fragment body-fragment-opt) append-fragments!(%1, %2); % non-statement-body-fragment (COMMA body-fragment-opt) append-fragments! (make(, source-location: @1, token: %1), %2); % non-statement-body-fragment (SEMICOLON body-fragment-opt) append-fragments! (make(, source-location: @1, token: %1), %2); % :type semicolon-fragment-opt semicolon-fragment-opt () make(, source-location: @0); % semicolon-fragment-opt (SEMICOLON body-fragment-opt) append-fragments! (make(, source-location: @1, token: %1), %2); % :type non-statement-list-fragment non-statement-list-fragment (simple-fragment list-fragment-opt) append-fragments!(%1, %2); % non-statement-list-fragment (COMMA list-fragment-opt) append-fragments! (make(, source-location: @1, token: %1), %2); % :type non-statement-basic-fragment non-statement-basic-fragment (simple-fragment basic-fragment-opt) append-fragments!(%1, %2); % :type simple-fragment simple-fragment (simple-fragment-token) make(, source-location: @1, token: %1); % simple-fragment (SHARP-PAREN constants DOT constant RIGHT-PAREN) // We can't use make-parsed-fragment directly because it would want a // , so it is just as easy to make the token-fragment // directly as it would be to make a just to pass to // make-parsed-fragment. make(, source-location: @0, token: make(, source-location: @0, kind: $parsed-constant-token, parse-tree: make(, sharable: #t, contents: as(, %2), tail: %4))); % simple-fragment (SHARP-PAREN constants-opt RIGHT-PAREN) // We can't use make-parsed-fragment directly because it would want a // , so it is just as easy to make the token-fragment // directly as it would be to make a just to pass to // make-parsed-fragment. make(, source-location: @0, token: make(, source-location: @0, kind: $parsed-constant-token, parse-tree: make(, sharable: #t, contents: as(, %2)))); % simple-fragment (SHARP-BRACKET constants-opt RIGHT-BRACKET) // We can't use make-parsed-fragment directly because it would want a // , so it is just as easy to make the token-fragment // directly as it would be to make a just to pass to // make-parsed-fragment. make(, source-location: @0, token: make(, source-location: @0, kind: $parsed-constant-token, parse-tree: make(, sharable: #t, contents: as(, %2)))); % simple-fragment (LEFT-PAREN body-fragment-opt RIGHT-PAREN) make(, left-token: %1, left-srcloc: @1, contents: %2, right-token: %3, right-srcloc: @3); % simple-fragment (LEFT-BRACKET body-fragment-opt RIGHT-BRACKET) make(, left-token: %1, left-srcloc: @1, contents: %2, right-token: %3, right-srcloc: @3); % simple-fragment (LEFT-BRACE body-fragment-opt RIGHT-BRACE) make(, left-token: %1, left-srcloc: @1, contents: %2, right-token: %3, right-srcloc: @3); % simple-fragment (function-macro-call) make-parsed-fragment(%1, source-location: @1); % :type simple-fragment-token simple-fragment-token (PARSED-EXPRESSION) %1; % simple-fragment-token (PARSED-CONSTANT) %1; % simple-fragment-token (PARSED-MACRO-CALL) %1; % simple-fragment-token (PARSED-VARIABLE-LIST) %1; % simple-fragment-token (PARSED-PARAMETER-LIST) %1; % simple-fragment-token (variable-name) %1; % simple-fragment-token (BINARY-OPERATOR) %1; % simple-fragment-token (TILDE) %1; % simple-fragment-token (SHARP-WORD) %1; % simple-fragment-token (DOT) %1; % simple-fragment-token (DOUBLE-COLON) %1; % simple-fragment-token (ARROW) %1; % simple-fragment-token (QUESTION) %1; % simple-fragment-token (DOUBLE-QUESTION) %1; % simple-fragment-token (QUESTION-EQUAL) %1; % simple-fragment-token (ELLIPSIS) %1; % simple-fragment-token (DOUBLE-SHARP) %1; % simple-fragment-token (OTHERWISE) %1; % simple-fragment-token (LITERAL) %1; % simple-fragment-token (STRING) %1; % simple-fragment-token (SYMBOL) %1; % ;;;; Defining Forms :type definition definition (PARSED-SPECIAL-DEFINITION) %1.token-parse-tree; % definition (definition-macro-call) %1; % definition (DEFINE MACRO MACRO-NAME main-rule-set auxiliary-rule-sets-opt END macro-and-name-opt) unless (%7 == #f | same-id?(%3, %7)) compiler-error("Macro name mismatch: %s isn't %s", %7, %3); end; make(, source-location: simplify-source-location(@0), name: %3, main-rule-set: %4, auxiliary-rule-sets: as(, %5)); % :type definition-macro-call definition-macro-call (PARSED-DEFINITION-MACRO-CALL) %1.token-parse-tree; % definition-macro-call (DEFINE modifiers-opt DEFINE-BODY-WORD body-fragment-opt END DEFINE-BODY-WORD MACRO-NAME) unless (same-id?(%3, %6)) compiler-error("Define-word mismatch: %s isn't %s", %6, %3); end; let first-word = first-word-in(%4); if (first-word) unless (same-id?(first-word, %7)) compiler-error("Name mismatch: %s isn't %s", %7, first-word); end; else compiler-error("Name mismatch: no name to match %s", %7); end; make(, source-location: simplify-source-location(@0), modifiers: %2, word: %3, fragment: %4); % definition-macro-call (DEFINE modifiers-opt DEFINE-BODY-WORD body-fragment-opt END DEFINE-BODY-WORD) unless (same-id?(%3, %6)) let first-word = first-word-in(%4); if (first-word) unless (same-id?(first-word, %6)) compiler-error ("Name or define-word mismatch: %s is neither %s nor %s", %6, %3, first-word); end; else compiler-error("Define-word mismatch: %s isn't %s", %6, %3); end; end; make(, modifiers: %2, word: %3, fragment: %4, source-location: simplify-source-location(@0)); % definition-macro-call (DEFINE modifiers-opt DEFINE-BODY-WORD body-fragment-opt END MACRO-NAME-NOT-DEFINE-BODY-WORD) let first-word = first-word-in(%4); if (first-word) unless (same-id?(first-word, %6)) compiler-error ("Name or define-word mismatch: %s is neither %s nor %s", %6, %3, first-word); end; else compiler-error("Define-word mismatch: %s isn't %s", %6, %3); end; make(, modifiers: %2, word: %3, fragment: %4, source-location: simplify-source-location(@0)); % definition-macro-call (DEFINE modifiers-opt DEFINE-BODY-WORD body-fragment-opt END) make(, modifiers: %2, word: %3, fragment: %4, source-location: simplify-source-location(@0)); % definition-macro-call (DEFINE modifiers-opt DEFINE-LIST-WORD list-fragment-opt) make(, modifiers: %2, word: %3, fragment: %4, source-location: simplify-source-location(@0)); % :type modifiers-opt modifiers-opt () #[]; % modifiers-opt (modifiers) as(, %1); % :type modifiers modifiers (UNRESERVED-NAME) stretchy-vector(%1); % modifiers (modifiers UNRESERVED-NAME) add!(%1, %2); % ;;;; Local declarations :type local-declaration local-declaration (PARSED-LOCAL-DECLARATION) %1.token-parse-tree; % local-declaration (LET bindings) make(, source-location: simplify-source-location(@0), variables: %2.bindings-variables, expression: %2.bindings-expression); % local-declaration (LET HANDLER operand EQUAL expression) make(, source-location: simplify-source-location(@0), type: %3, handler: %5); % local-declaration (LET HANDLER LEFT-PAREN expression COMMA arguments RIGHT-PAREN EQUAL expression) make(, source-location: simplify-source-location(@0), type: %4, options: as(, %6), handler: %9); % local-declaration (LOCAL local-methods) make(, source-location: simplify-source-location(@0), methods: as(, %2)); % :type local-methods local-methods (method-definition) stretchy-vector(%1); % local-methods (local-methods COMMA method-definition) add!(%1, %3); % :type bindings bindings (variable EQUAL expression) make(, variables: make(, fixed: vector(%1)), expression: %3); % bindings (LEFT-PAREN variable-list RIGHT-PAREN EQUAL expression) make(, variables: %2, expression: %5); % :type variable-list-opt variable-list-opt () make(); % variable-list-opt (variable-list) %1; % :type variable-list variable-list (PARSED-VARIABLE-LIST) %1.token-parse-tree; % variable-list (variables) make(, fixed: as(, %1)); % variable-list (variables COMMA REST variable) make(, fixed: as(, %1), rest: %4); % variable-list (REST variable) make(, rest: %2); % :type variables variables (variable) stretchy-vector(%1); % variables (variables COMMA variable) add!(%1, %3); % :type variable variable (variable-name) make(, name: %1); % variable (variable-name DOUBLE-COLON operand) make(, name: %1, type: %3); % :type variable-name variable-name (ordinary-name) %1; % ;;;; Expressions :type expression expression (expression-aux) reduce-binop-series(%1); % :type expression-aux expression-aux (binary-operand) make(, operand: %1, operand-srcloc: @1); % expression-aux (expression-aux BINARY-OPERATOR binary-operand) add-binop(%1, %2, %3, @3); % :type expression-no-symbol expression-no-symbol (expression-no-symbol-aux) reduce-binop-series(%1); % :type expression-no-symbol-aux expression-no-symbol-aux (binary-operand-no-symbol) make(, operand: %1, operand-srcloc: @1); % expression-no-symbol-aux (expression-no-symbol-aux BINARY-OPERATOR binary-operand) add-binop(%1, %2, %3, @3); % :type binary-operand binary-operand (SYMBOL) make(, source-location: simplify-source-location(@1), literal: %1.token-literal); % binary-operand (binary-operand-no-symbol) %1; % :type binary-operand-no-symbol binary-operand-no-symbol (operand) %1; % binary-operand-no-symbol (MINUS operand) make(, source-location: simplify-source-location(@0), function: make(, source-location: simplify-source-location(@1), id: make(, source-location: simplify-source-location(@1), kind: $raw-ordinary-word-token, symbol: #"negative", module: %1.token-module, uniquifier: %1.token-uniquifier)), arguments: vector(%2)); % binary-operand-no-symbol (TILDE operand) make(, source-location: simplify-source-location(@0), function: make(, source-location: simplify-source-location(@1), id: %1), arguments: vector(%2)); % :type operand operand (operand LEFT-PAREN arguments-opt RIGHT-PAREN) make(, source-location: simplify-source-location(@0), function: %1, arguments: %3); % operand (operand LEFT-BRACKET arguments-opt RIGHT-BRACKET) make(, source-location: simplify-source-location(@0), function: make(, source-location: simplify-source-location(@1), id: make(, source-location: simplify-source-location(@1), kind: $raw-ordinary-word-token, symbol: if (%3.size == 1) #"element"; else #"aref"; end, module: *Current-Module*)), arguments: apply(vector, %1, %3)); % operand (operand DOT variable-name) make(, source-location: simplify-source-location(@0), operand: %1, name: %3); % operand (PARSED-EXPRESSION) %1.token-parse-tree; % operand (leaf) %1; % :type arguments-opt arguments-opt () #[]; % arguments-opt (arguments) as(, %1); % :type arguments arguments (argument) if (instance?(%1, )) stretchy-vector(%1.head, %1.tail); else stretchy-vector(%1); end; % arguments (arguments COMMA argument) if (instance?(%3, )) add!(add!(%1, %3.head), %3.tail); else add!(%1, %3); end; % :type argument |type-union(, )| argument (SYMBOL expression) pair(make(, source-location: simplify-source-location(@1), literal: %1.token-literal), %2); % argument (expression-no-symbol) %1; % argument (SYMBOL) make(, source-location: simplify-source-location(@1), literal: %1.token-literal); % :type leaf leaf (literal-ref) %1; % leaf (variable-name) make(, source-location: simplify-source-location(@1), id: %1); % leaf (LEFT-PAREN expression RIGHT-PAREN) %2; % leaf (function-macro-call) %1; % leaf (statement) %1; % leaf (PARSED-MACRO-CALL) %1.token-parse-tree; % :type literal-ref literal-ref (LITERAL) make(, source-location: simplify-source-location(@1), literal: %1.token-literal); % literal-ref (STRING) make(, source-location: simplify-source-location(@1), literal: %1.token-literal); % literal-ref (STRING strings) make(, source-location: simplify-source-location(@0), literal: apply(concat-strings, %1.token-literal, %2)); % literal-ref (TRUE) make(, source-location: simplify-source-location(@1), literal: make()); % literal-ref (FALSE) make(, source-location: simplify-source-location(@1), literal: make()); % literal-ref (SHARP-PAREN constants DOT constant RIGHT-PAREN) make(, source-location: simplify-source-location(@0), literal: make(, sharable: #t, contents: as(, %2), tail: %4)); % literal-ref (SHARP-PAREN constants-opt RIGHT-PAREN) make(, source-location: simplify-source-location(@0), literal: make(, sharable: #t, contents: %2)); % literal-ref (SHARP-BRACKET constants-opt RIGHT-BRACKET) make(, source-location: simplify-source-location(@0), literal: make(, sharable: #t, contents: %2)); % literal-ref (PARSED-CONSTANT) make(, source-location: simplify-source-location(@1), literal: %1.token-parse-tree); % :type strings strings (STRING) stretchy-vector(%1.token-literal); % strings (strings STRING) add!(%1, %2.token-literal); % :type constants-opt constants-opt () #[]; % constants-opt (constants) as(, %1); % :type constants constants (constant) stretchy-vector(%1); % constants (constants COMMA constant) add!(%1, %3); % :type constant constant (raw-literal) %1; % constant (SYMBOL) %1.token-literal; % :type raw-literal raw-literal (LITERAL) %1.token-literal; % raw-literal (STRING) %1.token-literal; % raw-literal (STRING strings) apply(concat-strings, %1.token-literal, %2); % raw-literal (TRUE) make(); % raw-literal (FALSE) make(); % raw-literal (SHARP-PAREN constants DOT constant RIGHT-PAREN) make(, sharable: #t, contents: as(, %2), tail: %4); % raw-literal (SHARP-PAREN constants-opt RIGHT-PAREN) make(, sharable: #t, contents: %2); % raw-literal (SHARP-BRACKET constants-opt RIGHT-BRACKET) make(, sharable: #t, contents: %2); % raw-literal (PARSED-CONSTANT) %1.token-parse-tree; % :type function-macro-call function-macro-call (FUNCTION-WORD LEFT-PAREN body-fragment-opt RIGHT-PAREN) make(, source-location: simplify-source-location(@0), word: %1, fragment: %3); % ;;;; Statements :type statement statement (BEGIN-WORD body-fragment-opt end-clause) if (%3 & ~same-id?(%1, %3)) compiler-error("Begin-word mismatch: %s isn't %s", %3, %1); end; make(, source-location: simplify-source-location(@0), word: %1, fragment: %2); % :type end-clause |false-or()| end-clause (END) #f; % end-clause (END BEGIN-WORD) %2; % ;;;; Case bodies. ;// Case-body-1's end in a case-label. Case-body-2's end in constituents. ;// Either kind is a valid case-body, but can be extended differently. ;// This seperation is necessary in order to resolve the various conflicts ;// inherit in the original production: ;// ;// case-body: ;// case-label constituents-OPT ; ... ;// ;// If left as is, then we can't tell what to do when we hit a ;// semicolon. Specifically, it can either seperate two constituents, ;// seperate two case clauses, or terminate the case-body. Splitting ;// case-body into case-body-1 and case-body-2 allows us to talk about ;// the semicolon token ourselves, which means it no longer might have ;// to be reduced over (i.e. we no longer have to tell the difference ;// between a semicolon that seperates two constituents from one that ;// seperates two case clauses. ;// ;// To fix the remaining problem, we intoduce the -semi productions that are ;// the same thing as the sans -semi production, except followed by a ;// semicolon. This allows us to shift the semicolon that follows a case-body ;// without having to reduce the entire case-body. :type case-body-opt case-body-opt () make(, source-location: @0); % case-body-opt (SEMICOLON) make(, source-location: @1, token: %1); % case-body-opt (case-body-1) %1.fragment; % case-body-opt (case-body-1-semi) %1.fragment; % case-body-opt (case-body-2) finish-case-body(%1); %1.fragment; % case-body-opt (case-body-2-semi) finish-case-body(%1); %1.fragment; % :type case-body-1 case-body-1 (case-label) // Make a new state and add the label. make(, fragment: %1); % case-body-1 (case-body-1-semi case-label) // Add the label. push-case-fragment(%1, %2); %1; % case-body-1 (case-body-2-semi case-label) // Make a body out of the accumulated constituents and push them. finish-case-body(%1); // Push the label. push-case-fragment(%1, %2); %1; % :type case-body-1-semi case-body-1-semi (case-body-1 SEMICOLON) // Add the semicolon to the fragment. push-case-fragment (%1, make(, source-location: @2, token: %2)); %1; % :type case-body-2 case-body-2 (case-label constituent) // make a new state from the case-label and constituent. make(, fragment: %1, constituents: stretchy-vector(%2), constituents-srcloc: @2); % case-body-2 (case-body-1-semi case-label constituent) // append the case-label to the fragment, prime the body with constituent push-case-fragment(%1, %2); push-case-constituent(%1, %3, @3); %1; % case-body-2 (case-body-2-semi case-label constituent) // append the body, the semi, and the case-label to the fragment. finish-case-body(%1); push-case-fragment(%1, %2); // Start a new body with the constituent. push-case-constituent(%1, %3, @3); %1; % case-body-2 (case-body-2-semi constituent) // add the constituent to the partial body. push-case-constituent(%1, %2, @2); %1; % :type case-body-2-semi case-body-2-semi (case-body-2 SEMICOLON) // set the semicolon. We don't push it immediately because it might just // be separating two constituents, in which case we are going to want to // drop it. %1.semicolon := make(, source-location: @2, token: %2); %1; % :type case-label case-label (case-label-expressions ARROW) append-fragments! (%1, make(, source-location: @2, token: %2)); % case-label (LEFT-PAREN expression COMMA case-label-expressions RIGHT-PAREN ARROW) append-fragments! (make(, left-token: %1, left-srcloc: @1, contents: append-fragments! (append-fragments! (make-parsed-fragment(%2, source-location: @2), make(, source-location: @3, token: %3)), %4), right-token: %5, right-srcloc: @5), make(, source-location: @6, token: %6)); % case-label (OTHERWISE) make(, source-location: @1, token: %1); % case-label (OTHERWISE ARROW) append-fragments!(make(, source-location: @1, token: %1), make(, source-location: @2, token: %2)); % :type case-label-expressions case-label-expressions (expression) make-parsed-fragment(%1, source-location: @1); % case-label-expressions (case-label-expressions COMMA expression) append-fragments! (append-fragments! (%1, make(, source-location: @2, token: %2)), make-parsed-fragment(%3, source-location: @3)); % ;;;; Methods. :type method-definition method-definition (method-and-name method-body END method-and-name-opt) if (%4 & ~same-id?(%1, %4)) compiler-error("Name mismatch: %s isn't %s", %4.token-symbol, %1.token-symbol); end; %2.method-name := %1; %2; % :type method-and-name method-and-name (variable-name) if (%1.token-symbol == #"method") compiler-fatal-error("Parse error at or before %s", %1); end; %1; % method-and-name (variable-name variable-name) unless (%1.token-symbol == #"method") compiler-fatal-error("Parse error at or before %s", %1); end; %2; % method-and-name (non-variable-name variable-name) unless (%1.token-symbol == #"method") compiler-fatal-error("Parse error at or before %s", %1); end; %2; % :type method-and-name-opt |false-or()| method-and-name-opt () #f % method-and-name-opt (variable-name) unless (%1.token-symbol == #"method") %1; end; % method-and-name-opt (variable-name variable-name) unless (%1.token-symbol == #"method") compiler-fatal-error("Parse error at or before %s", %1); end; %2; % method-and-name-opt (non-variable-name) unless (%1.token-symbol == #"method") compiler-fatal-error("Parse error at or before %s", %1); end; #f; % method-and-name-opt (non-variable-name variable-name) unless (%1.token-symbol == #"method") compiler-fatal-error("Parse error at or before %s", %1); end; %2; % :type method-body method-body (LEFT-PAREN parameter-list-opt RIGHT-PAREN semi-opt body-opt) make(, parameters: %2, body: %5, source-location: simplify-source-location(@0)); % method-body (LEFT-PAREN parameter-list-opt RIGHT-PAREN ARROW variable SEMICOLON body-opt) make(, parameters: %2, returns: make(, fixed: vector(%5)), body: %7, source-location: simplify-source-location(@0)); % method-body (LEFT-PAREN parameter-list-opt RIGHT-PAREN ARROW LEFT-PAREN variable-list-opt RIGHT-PAREN semi-opt body-opt) make(, parameters: %2, returns: %6, body: %9, source-location: simplify-source-location(@0)); % :type parameter-list-opt parameter-list-opt (PARSED-PARAMETER-LIST) %1.token-parse-tree; % parameter-list-opt () make(); % parameter-list-opt (parameters) make(, fixed: as(, %1)); % parameter-list-opt (parameters COMMA next-rest-key-parameter-list) %3.varlist-fixed := as(, %1); %3; % parameter-list-opt (next-rest-key-parameter-list) %1; % :type next-rest-key-parameter-list next-rest-key-parameter-list (NEXT variable-name) make(, next: %2); % next-rest-key-parameter-list (NEXT variable-name COMMA rest-key-parameter-list) %4.paramlist-next := %2; %4; % next-rest-key-parameter-list (rest-key-parameter-list) %1; % :type rest-key-parameter-list rest-key-parameter-list (REST variable) make(, rest: %2); % rest-key-parameter-list (REST variable COMMA key-parameter-list) %4.varlist-rest := %2; %4; % rest-key-parameter-list (key-parameter-list) %1; % :type key-parameter-list key-parameter-list (KEY keyword-parameters-opt) make(, keys: %2); % key-parameter-list (KEY COMMA ALL-KEYS) make(, keys: #[], all-keys: #t); % key-parameter-list (KEY keyword-parameters-comma ALL-KEYS) make(, keys: as(, %2), all-keys: #t); % :type parameters parameters (parameter) stretchy-vector(%1); % parameters (parameters COMMA parameter) add!(%1, %3); % parameter (variable) %1; % :type parameter parameter (variable-name DOUBLE-EQUAL expression) let singleton-name = make(, source-location: simplify-source-location(@2), kind: $raw-ordinary-word-token, symbol: #"singleton", module: %2.token-module, uniquifier: %2.token-uniquifier); let singleton-varref = make(, source-location: simplify-source-location(@2), id: singleton-name); let funcall = make(, source-location: source-location-spanning(@2, @3), function: singleton-varref, arguments: vector(%3)); make(, name: %1, type: funcall); % :type keyword-parameters-opt keyword-parameters-opt () #[]; % keyword-parameters-opt (keyword-parameters) as(, %1); % :type keyword-parameters keyword-parameters (keyword-parameter) stretchy-vector(%1); % keyword-parameters (keyword-parameters-comma keyword-parameter) add!(%1, %2); % :type keyword-parameters-comma keyword-parameters-comma (keyword-parameters COMMA) %1; % :type keyword-parameter keyword-parameter (keyword-opt variable default-opt) make(, name: %2.param-name, type: %2.param-type, keyword: if (%1) %1.token-literal.literal-value; else %2.param-name.token-symbol; end, default: %3); % :type keyword-opt |false-or()| keyword-opt () #f; % keyword-opt (SYMBOL) %1; % :type default-opt |false-or()| default-opt () #f; % default-opt (EQUAL expression) %2; % ;;;; Macros, patterns, and templates :type macro-and-name-opt |false-or()| macro-and-name-opt () #f; % macro-and-name-opt (MACRO) #f; % macro-and-name-opt (MACRO-NAME) %1; % macro-and-name-opt (MACRO MACRO-NAME) %2; % :type main-rule-set main-rule-set (main-rules) make(, rules: as(, %1)); % :type main-rules main-rules (main-rule) stretchy-vector(%1); % main-rules (main-rules main-rule) add!(%1, %2); % :type main-rule main-rule (LEFT-BRACE DEFINE pattern RIGHT-BRACE ARROW rhs) make-define-rule(%3, %6); % main-rule (LEFT-BRACE variable-name pattern RIGHT-BRACE ARROW rhs) make-statement-or-function-rule(%2, %3, %6); % :type rhs