Module: dfmc-reader Copyright: Original Code is Copyright (c) 1995-2004 Functional Objects, Inc. All rights reserved. License: Functional Objects Library Public License Version 1.0 Dual-license: GNU Lesser General Public License Warranty: Distributed WITHOUT WARRANTY OF ANY KIND define thread variable *fragment-context* = #f; define constant $nowhere = #f; define macro nowhere-or { nowhere-or(?:expression) } => { false-or(?expression) } end macro; define macro with-fragment-info { with-fragment-info (?frag:expression) ?:body end } => { ?body } end macro; //// Fragment classes. define constant $literal-token = $number-token; define abstract class () slot fragment-record :: false-or() = #f, init-keyword: record:; slot fragment-source-position = $nowhere, init-keyword: source-position:; end class; define generic fragment-source-location (f :: ) => (loc :: nowhere-or()); define method fragment-source-location (f :: ) => (loc :: nowhere-or()); record-position-as-location(fragment-record(f), fragment-source-position(f)) end method; // TODO: Is this hack still used? If not, tighten the arg decl above. define method fragment-source-location (f :: ) => (loc :: nowhere-or()) // between(f.first, f.last); fragment-source-location(f.first); end method; define sealed domain make (subclass()); define sealed domain initialize (); define compiler-open class () end; define dont-copy-object using ; define dont-copy-object using ; // TODO: Remove unused protocol? /* define generic fragment-start-source-location (f :: ) => (loc :: ); define generic fragment-end-source-location (f :: ) => (loc :: ); define method fragment-start-source-location (f :: ) => (loc :: ) source-location-start-source-location(fragment-source-location(f)) end method; define method fragment-end-source-location (f :: ) => (loc :: ) source-location-end-source-location(fragment-source-location(f)) end method; */ define inline method compute-position-between* (p1, p2) let start-offset = p1.source-position-start-offset; let end-offset = p2.source-position-end-offset; if (range-source-offset-greater-than?(start-offset, end-offset)) make-range-position(p2.source-position-start-offset, p1.source-position-end-offset); else make-range-position(start-offset, end-offset); end if end method; define method compute-position-between (p1, p2) if (~p1) p2 elseif (~p2) p1 else compute-position-between*(p1, p2) end; end method; define method position-between (f1 == #f, f2 == #f) #f end; define method position-between (f1 == #f, f2) position-between(#(), f2); end; define method position-between (f1, f2 == #f) position-between(f1, #()); end method; define method position-between (f1 :: , f2 :: ) compute-position-between (f1.fragment-source-position, f2.fragment-source-position) end method; define method position-between (f1 :: , f2 :: ) if (empty?(f2)) f1.fragment-source-position; else position-between(f1, f2.last) end; end method; define method position-between (f1 :: , f2 :: ) position-between(if (empty?(f1)) #f else f1.first end, if (empty?(f2)) #f else f2.last end) end method; define method position-between (f2 :: , f1 :: ) if (empty?(f2)) f1.fragment-source-position else position-between(f2.first, f1) end; end method; define method position-spanning (f*) if (empty?(f*)) $nowhere else // format-out("First loc: %=\n", fragment-source-location(f*.first)); // format-out("Last loc: %=\n", fragment-source-location(f*.last)); position-between(f*.first, f*.last); end; end method; define method spanning (f*) let pos = position-spanning(f*); if (pos) record-position-as-location(f*.first.fragment-record, pos) else $nowhere end; end method; define abstract class () end; define abstract class () end; define generic fragment-kind (fragment :: ) => kind; // Hygiene mixins. define thread variable *expansion-identifier* = #f; define class () end; define inline function do-with-new-hygiene-context (f, mac) ignore(mac); dynamic-bind (*expansion-identifier* = make()) f(); end; end function; define macro with-new-hygiene-context { with-new-hygiene-context (?mac:expression) ?:body end } => { do-with-new-hygiene-context (method () ?body end, ?mac) } end macro; define function make-unique-local-variable-name-fragment (name) with-new-hygiene-context (#"unknown") make(, name: as(, concatenate("_unique-", as(, name))), record: #f, source-position: #f); end; end function; define abstract class () end class; define generic hygienic-fragment-info (f :: ) => info; define generic hygienic-fragment-context (info) => context; define method hygienic-fragment-context (context) => context; context end method; define method fragment-context (f :: ) hygienic-fragment-context(f.hygienic-fragment-info) end method; define generic hygienic-fragment-origin (info) => origin; define method hygienic-fragment-origin (context) => origin; #f end method; define method fragment-origin (f :: ) hygienic-fragment-origin(f.hygienic-fragment-info) end method; // This is only used when there is a non-#f origin (less than 5% of the cases) define made-inline class () constant slot hygienic-fragment-context, required-init-keyword: context:; constant slot hygienic-fragment-origin, required-init-keyword: origin:; end class; define sealed domain make (subclass()); define sealed domain initialize (); // TODO: PERFORMANCE: get rid of this method... /* define method make (class :: subclass(), #rest initargs, #key context = *fragment-context*, origin = *expansion-identifier*) => fragment :: ; apply(next-method, class, info: if (origin) make(, context: context, origin: origin) else context end, initargs) end method; */ define inline method initialize (f :: , #key context = *fragment-context*, origin = *expansion-identifier*) => () next-method(); if (origin) hygienic-fragment-info(f) := make(, context: context, origin: origin); else hygienic-fragment-info(f) := context end; end method; define abstract class () slot fragment-value, init-keyword: value:; end class; define constant = ; // TODO: CORRECTNESS: Provide a subclass of // for use for "other values", rather than instantiating this one. define /* abstract */ class (, ) end class; define method fragment-kind (f :: ) => kind; $literal-token end method; define /* abstract */ class () end class; define class () inherited slot fragment-value = #t; // keyword value: = #t; end class; define class () inherited slot fragment-value = #f; // keyword value: = #f; end class; define /* abstract */ class () end class; define method fragment-kind (f :: ) => kind; $character-literal-token end method; define /* abstract */ class () end class; define method fragment-kind (f :: ) => kind; $string-token end method; define /* abstract */ class () end class; define method fragment-kind (f :: ) => kind; $symbol-token end method; define method as (class == , name :: ) => (symbol :: ) fragment-value(name); end method; // This distinction is only maintained for displaying parsed code as // it was read. define class () end; define class () end; define /* abstract */ class (, ) end class; define method fragment-kind (f :: ) => kind; $literal-token end method; // TODO: CORRECTNESS: Decide how to represent big integers. define /* abstract */ class () end; define class () end; define class () end; define abstract class (, ) constant slot fragment-elements, required-init-keyword: elements:; inherited slot fragment-value = #f; // keyword value: = #f; end class; // TODO: CORRECTNESS: Get this representation right. We need to be able // to represent both fragments from the parser and literal objects // made given just a list value. define class () end; define method fragment-kind (f :: ) => kind; $parsed-list-constant-token; end method; define class () end; define inline method initialize (f :: , #key) if (~fragment-value(f)) fragment-value(f) := map-as(, fragment-value, fragment-elements(f)); end; end method; define class () constant slot fragment-improper-tail, required-init-keyword: improper-tail:; end class; define inline method initialize (f :: , #key) if (~fragment-value(f)) for (val = fragment-value(fragment-improper-tail(f)) then pair(fragment-value(next), val), next in reverse(fragment-elements(f))) finally fragment-value(f) := val; end; end; end method; define class () end; define inline method initialize (f :: , #key) if (~fragment-value(f)) fragment-value(f) := map-as(, fragment-value, fragment-elements(f)); end; end method; define method fragment-kind (f :: ) => kind; $parsed-vector-constant-token; end method; define abstract class () end; define class () end; define method fragment-kind (f :: ) => kind; $dot-token end method; define abstract class () end; define class () end; define method fragment-kind (f :: ) => kind; $comma-token end method; define class () end; define method fragment-kind (f :: ) => kind; $semicolon-token end method; define class () end; define method fragment-kind (f :: ) => kind; $colon-colon-token end method; define class () end; define method fragment-kind (f :: ) => kind; $equal-greater-token end method; define abstract class () end; define class () end; define method fragment-kind (f :: ) => kind; $hash-next-token end method; define class () end; define method fragment-kind (f :: ) => kind; $hash-rest-token end method; define class () end; define method fragment-kind (f :: ) => kind; $hash-key-token end method; define class () end; define method fragment-kind (f :: ) => kind; $hash-all-keys-token end method; define abstract class () end; define abstract class () end; define class () end; define method fragment-kind (f :: ) => kind; $lparen-token end method; define class () end; define method fragment-kind (f :: ) => kind; $rparen-token end method; define class (, ) // constant slot hygienic-fragment-info, required-init-keyword: info:; slot hygienic-fragment-info = #f, init-keyword: info:; end class; define method fragment-kind (f :: ) => kind; $lbracket-token end method; define class () end; define method fragment-kind (f :: ) => kind; $rbracket-token end method; define class () end; define method fragment-kind (f :: ) => kind; $lbrace-token end method; define class () end; define method fragment-kind (f :: ) => kind; $rbrace-token end method; define class () end; define method fragment-kind (f :: ) => kind; $hash-lparen-token end method; define class () end; define method fragment-kind (f :: ) => kind; $hash-lbracket-token end method; define class (, ) // constant slot hygienic-fragment-info, required-init-keyword: info:; slot hygienic-fragment-info = #f, init-keyword: info:; end class; define method fragment-kind (f :: ) => kind; $hash-lbrace-token end method; // Macro system puntuation. define class () end; define method fragment-kind (f :: ) => kind; $query-token end method; define class () end; define method fragment-kind (f :: ) => kind; $query-query-token end method; define class () end; define method fragment-kind (f :: ) => kind; $query-equal-token end method; define class () end; define method fragment-kind (f :: ) => kind; $query-at-token end method; define class (, ) // constant slot hygienic-fragment-info, required-init-keyword: info:; slot hygienic-fragment-info = #f, init-keyword: info:; end class; define method fragment-kind (f :: ) => kind; $ellipsis-token end method; define class (, ) constant slot fragment-kind = $constrained-name-token, init-keyword: kind:; // constant slot hygienic-fragment-info, required-init-keyword: info:; slot hygienic-fragment-info = #f, init-keyword: info:; constant slot fragment-name, required-init-keyword: name:; constant slot fragment-constraint, required-init-keyword: constraint:; end class; define class () end; define method fragment-kind (f :: ) => kind; $hash-hash-token end method; define class () constant slot fragment-escaped-fragment, required-init-keyword: escaped-fragment:; end class; define method fragment-kind (f :: ) => kind; $escaped-substitution-token end method; define inline function make-escaped-punctuation (class, source-location :: ) let rec = source-location.source-location-record; let pos = source-location.source-location-source-position; make(, record: rec, source-position: pos, escaped-fragment: make(class, record: rec, source-position: pos)); end function; define function make-escaped-query (lexer, source-location) make-escaped-punctuation(, source-location); end function; define function make-escaped-query-query (lexer, source-location) make-escaped-punctuation(, source-location); end function; define function make-escaped-query-equal (lexer, source-location) make-escaped-punctuation(, source-location); end function; define function make-escaped-ellipsis (lexer, source-location) make-escaped-punctuation(, source-location); end function; define function make-escaped-colon-colon (lexer, source-location) make-escaped-punctuation(, source-location); end function; define function make-escaped-hash-next-fragment (lexer, source-location) make-escaped-punctuation(, source-location); end function; define function make-escaped-hash-rest-fragment (lexer, source-location) make-escaped-punctuation(, source-location); end function; define function make-escaped-hash-key-fragment (lexer, source-location) make-escaped-punctuation(, source-location); end function; define function make-escaped-hash-all-keys-fragment (lexer, source-location) make-escaped-punctuation(, source-location); end function; //// Names and stuff. define class (, ) constant slot fragment-name :: , init-keyword: name:; end class; define method same-name-when-local? (name1 :: , name2 :: ) => (same? :: ) fragment-name(name1) == fragment-name(name2) & fragment-origin(name1) == fragment-origin(name2) end method; define method as (class == , name :: ) => (symbol :: ) fragment-name(name); end method; define method as (class == , name :: ) => (symbol :: ) as(, fragment-name(name)); end method; define method fragment-name-string (name :: ) => (name-string :: ) as(, fragment-name(name)); end method; // TODO: Turn all this into a sensible inheritance heirarchy again! define class (, ) end; define method hygienic-fragment-info-setter (info, var :: ) => (info) // Should assert. info end method; define constant fragment-identifier = fragment-name; // A fragment with everything on it. define made-inline class () // constant slot hygienic-fragment-info, // required-init-keyword: info:; slot hygienic-fragment-info = #f, init-keyword: info:; constant slot fragment-kind = $unreserved-name-token, init-keyword: kind:; end; // A hygiene-less Dylan variable name. define made-inline class () constant slot fragment-kind = $unreserved-name-token, init-keyword: kind:; end; define method hygienic-fragment-info (var :: ) => (info); #f // indicates the Dylan module end method; define made-inline class () end class; define method fragment-kind (var :: ) => kind; $unreserved-name-token end method; define method hygienic-fragment-info (var :: ) => (info); let rec = fragment-record(var); rec & compilation-record-module(rec) end method; // As above, but always in the Dylan library. This allows the record/source // position not to have to match the module context. define made-inline class () end class; define method hygienic-fragment-info (var :: ) => (info); #f // indicates the Dylan module end method; // A fragment without a hygiene context and with a derivable module context. define made-inline class () constant slot fragment-kind = $unreserved-name-token, init-keyword: kind:; end; define method hygienic-fragment-info (var :: ) => (info); let rec = fragment-record(var); rec & compilation-record-module(rec) end method; define inline method make (class == , #rest initargs, #key kind = $unreserved-name-token, context = *fragment-context*, origin = *expansion-identifier*, record, source-position, name, #all-keys) => (var :: ); if (origin) // If we have a hygiene context, we just go the whole hog. // format-out("Origin special: %s, %=\n", name, context); apply(make, , initargs) elseif (~context) // If we're in the Dylan library, choose the most compact rep we // have. if (kind == $unreserved-name-token) make(, name: name, record: record, source-position: source-position); else make(, name: name, kind: kind, record: record, source-position: source-position); end; else // We're outside the Dylan library, but we can still have a more compact // rep if the source location matches the expansion module context. let simple? = record & context; let cr = simple? & instance?(record, ) & record; let m = cr & compilation-record-module(cr); if (simple? & (m == context)) if (kind == $unreserved-name-token) make(, name: name, record: cr, source-position: source-position); else make(, name: name, kind: kind, record: cr, source-position: source-position); end; else // format-out("Special: %s, %=\n", name, context); apply(make, , initargs) end; end; end method; // Implemented in dfmc-flow-graph define compiler-open generic fragment-module (fragment :: ) => (module); define function dylan-variable-name (name) make(, name: name, record: #f, source-position: #f); end function; define sideways method make-variable-name-fragment (name) => (variable-name) dylan-variable-name(name) end method; define method make-variable-name-fragment-in-module (name, module) => (new-name :: ) make(, name: name, context: module, record: #f, source-position: #f) end method; define method make-variable-name-like (name :: , #rest keys) => (new-name :: ) apply(make, , context: fragment-context(name), origin: fragment-origin(name), keys); end method; define method splice-name-hygienically (name :: , prefix :: , suffix :: ) => (new-name :: ) let spliced-name = as(, concatenate(prefix, fragment-name-string(name), suffix)); make-variable-name-like(name, record: fragment-record(name), source-position: fragment-source-position(name), kind: classify-expansion-word-in(fragment-context(name), spliced-name), name: spliced-name); end method; define method suffix-name-hygienically (name :: , suffix :: ) => (new-name :: ) make-variable-name-like(name, record: fragment-record(name), source-position: fragment-source-position(name), name: as(, concatenate(fragment-name-string(name), suffix))); end method; define class () end; define class () end; define class (, ) inherited slot fragment-kind = $binary-operator-only-token; // keyword kind: = $binary-operator-only-token; end class; define class () inherited slot fragment-kind = $unary-operator-only-token; // keyword kind: = $unary-operator-only-token; end class; define class (, ) inherited slot fragment-kind = $unary-and-binary-operator-token; // keyword kind: = $unary-and-binary-operator-token; end class; define class (, ) inherited slot fragment-kind = $equal-token; inherited slot fragment-name = #"="; // keyword kind: = $equal-token; // keyword name: = #"="; end class; define class () constant slot fragment-fragments, required-init-keyword: fragments:; end class; // We compute sequence fragment locations lazily on the grounds that they're // only usually needed for error reporting, or only accessed once if they // are used for anything else. define method fragment-source-location (f :: ) => (loc :: nowhere-or()); // format-out(">>>> Sequence source location of %=\n", f); let f* = fragment-fragments(f); if (empty?(f*)) next-method(); else let f1 = f*.first; let f2 = f*.last; if (fragment-record(f1) == fragment-record(f2)) record-position-as-location (fragment-record(f1), position-between(f1, f2)); else // Our final fallback is to prune out everything macro-generated, and // try again. let user-f* = choose(fragment-record, f*); let f1 = user-f*.first; let f2 = user-f*.last; if (fragment-record(f1) == fragment-record(f2)) record-position-as-location (fragment-record(f1), position-between(f1, f2)); else #f end; end; end; end method; // TODO: Remove - hack. This because of the canonicalisation of a // wildcard match to a single element if of length one. define method fragment-fragments (f :: ) list(f) end; define abstract class () slot fragment-function, required-init-keyword: function:; constant slot fragment-arguments, required-init-keyword: arguments:; end class; // TODO: CORRECTNESS: Generating a macro call for an array syntax call // where appropriate. Same thing for -setter calls, if they don't simply // always get reparsed. define class () end; define class () end; define class () end; define class () end; define class () end; // TODO: CORRECTNESS: Need to reclassify the call as a macro if necessary. // Perhaps we should do this transformation elsewhere? Seel also how // element is handled. define inline method initialize (call :: , #key) next-method(); let func = fragment-function(call); if (fragment-name(func) == #"-") fragment-function(call) := make-variable-name-like(func, record: fragment-record(func), source-position: fragment-source-position(func), name: #"negative", kind: $unreserved-name-token); end; end method; define class () constant slot fragment-constituents, required-init-keyword: constituents:; end class; define method fragment-kind (f :: ) => kind; $parsed-macro-call-token; end method; define function body-fragment (f*) let rec = if (f* ~== #()) f*.head.fragment-record end; collecting (folded) iterate walk (cursor = f*) if (cursor == #()) make(, record: rec, source-position: position-spanning(f*), constituents: f*); else let lead = cursor.head; if (instance?(lead, )) let sub-body = body-fragment(cursor.tail); collect-into (folded, make(, record: rec, source-position: position-between(f*.head, sub-body), declaration-fragment: lead, body-fragment: sub-body)); let folded = collected(folded); make(, record: rec, source-position: position-spanning(folded), constituents: folded); else collect-into(folded, lead); walk(cursor.tail); end; end; end; end; end function; define function empty-body-fragment () make(, record: #f, source-position: $nowhere, constituents: #()); end function; define abstract class () end; define abstract class () end; define class () end; define abstract class () constant slot fragment-left-delimiter, required-init-keyword: left-delimiter:; constant slot fragment-nested-fragments, required-init-keyword: nested-fragments:; constant slot fragment-right-delimiter, required-init-keyword: right-delimiter:; inherited slot fragment-record = #f; inherited slot fragment-source-position = $nowhere; // keyword record: = #f; // keyword source-position: = $nowhere; end class; define method nested-fragment? (f) => (well? :: , left, right) values(#f, #f, #f); end method; define method nested-fragment? (f :: ) => (well? :: , left :: , right :: ) values(#t, fragment-left-delimiter(f), fragment-right-delimiter(f)) end method; define class () end; define class () end; define class () end; //// Conditional compilation fragments. /* CMU only define abstract class () constant slot fragment-kind, required-init-keyword: kind:; end; define class () end; define class () end; define class () end; define class () end; */ //// Pseudo-fragments used to delimit the reparsing of macro constraints. define class () constant slot fragment-kind, required-init-keyword: kind:; inherited slot fragment-record = #f; inherited slot fragment-source-position = $nowhere; // keyword record: = #f; // keyword source-position: = $nowhere; end class; define constant $start-token-constraint = make(, kind: $token-constraint-token); define constant $start-name-constraint = make(, kind: $name-constraint-token); define constant $start-expression-constraint = make(, kind: $expression-constraint-token); define constant $start-variable-constraint = make(, kind: $variable-constraint-token); define constant $start-body-constraint = make(, kind: $body-constraint-token); define constant $start-case-body-constraint = make(, kind: $case-body-constraint-token); define constant $start-property-list-constraint = make(, kind: $property-list-constraint-token); define constant $start-fragment-constraint = make(, kind: $fragment-constraint-token); define constant $end-constraint = make(, kind: $end-constraint-token); //// Special fragments. define abstract class () constant slot fragment-kind, init-keyword: kind:; end; define class () inherited slot fragment-kind = $eof-token; // keyword kind: = $eof-token; end class; define class () end; define method end-of-modifiers-marker? (fragment) => (well? :: ) // Temporarily, for bootstrapping purposes, any defining word matches // as an end modifier. TODO: Remove this bootstrapping hack. instance?(fragment, ) /* | (instance?(fragment, ) & definer-or-merged-token-class?(fragment-kind(fragment))) */ end method; // define constant $eof-marker = make(, // record: #f, // source-position: $nowhere); //// Create a fragment value from a Dylan value. define method as-fragment-value (object) object end; define method as-fragment-float-value (class, object) object end; //// A model object fed back into the compiler as syntax. define class () end; define method parsed-literal (o) make(, record: #f, source-position: $nowhere, value: o); end method; define method fragment-kind (f :: ) => kind; $literal-token; end method; // define method as-fragment (o) // make-in-expansion(, value: o); // end method; //// The unbound object. // The unbound class is defined as a compiler space object and mapped to // to make it consistent with the unique literals #t, #f, etc. It's also // allowed to appear as a literal in code. define class () end; define constant $unbound = make(); define dont-copy-object using ; //// Coercion. define compiler-open generic as-fragment (object); define method as-fragment (o :: ) parsed-literal(o) end method; //// Reparsing. define method fragment-kind (f :: ) => kind; $parsed-function-call-token; end method; //// Shallow parsing. define class () slot fragment-macro, required-init-keyword: macro:; constant slot fragment-body-fragment, required-init-keyword: body-fragment:; constant slot fragment-end-word = #f, init-keyword: end-word:; end class; define method fragment-kind (f :: ) => kind; $parsed-macro-call-token; end method; define method fragment-argument (f :: ) fragment-body-fragment(f); end method; define program-warning slot condition-statement-name, init-keyword: statement-name:; format-string "Mismatched end clause in %s statement."; format-arguments statement-name; end program-warning; define function verify-statement-tail (macro-word :: , tail :: false-or()) => () if (tail & fragment-name(tail) ~== #"end") if (fragment-name(tail) ~== fragment-name(macro-word)) note(, source-location: record-position-as-location (fragment-record(macro-word), position-between(macro-word, tail)), statement-name: macro-word); end; end; end function; define class () slot fragment-macro, required-init-keyword: macro:; constant slot fragment-body-fragment, required-init-keyword: body-fragment:; end class; define method fragment-kind (f :: ) => kind; $parsed-macro-call-token; end method; define method fragment-argument (f :: ) fragment-body-fragment(f); end method; define class () slot fragment-macro, required-init-keyword: macro:; constant slot fragment-list-fragment, required-init-keyword: list-fragment:; end class; define method fragment-kind (f :: ) => kind; $parsed-local-declaration-token; end method; define class () constant slot fragment-declaration-fragment, required-init-keyword: declaration-fragment:; constant slot fragment-body-fragment, required-init-keyword: body-fragment:; end class; define method fragment-macro (f :: ) fragment-macro(fragment-declaration-fragment(f)); end method; define method fragment-kind (f :: ) => kind; $parsed-macro-call-token; end method; define abstract class () slot fragment-macro; constant slot fragment-modifiers, required-init-keyword: modifiers:; constant slot fragment-define-word, required-init-keyword: define-word:; end class; define /* abstract */ class () constant slot fragment-end, required-init-keyword: end:; constant slot fragment-tail-name-1 = #f, init-keyword: tail-name-1:; constant slot fragment-tail-name-2 = #f, init-keyword: tail-name-2:; end class; ignore(fragment-end); define program-warning slot condition-definition-name, init-keyword: definition-name:; format-string "Mismatched end clause in %s definition."; format-arguments definition-name; end program-warning; define function verify-definition-tail (lead-word :: , macro-word :: , maybe-name :: false-or(), tail :: ) => () let name-1 = fragment-tail-name-1(tail); let name-2 = fragment-tail-name-2(tail); if (name-2) // We know we have both a macro word and a name. if (fragment-name(name-1) ~== fragment-name(macro-word) | (maybe-name & fragment-name(name-2) ~== fragment-name(maybe-name))) note(, source-location: record-position-as-location (fragment-record(lead-word), position-between(lead-word, tail)), definition-name: macro-word); end; elseif (name-1) // We have one name that could validly be either the macro word or // the name of the thing being defined. if ((fragment-name(name-1) ~== fragment-name(macro-word) & (definer-or-merged-token-class?(fragment-kind(name-1)) | (maybe-name & fragment-name(name-1) ~== fragment-name(maybe-name))))) note(, source-location: record-position-as-location (fragment-record(lead-word), position-between(lead-word, tail)), definition-name: macro-word); end; end; end function; define function maybe-defined-name (fragments :: ) => (maybe-name :: false-or()) let name = first(fragments, default: #f); if (name & instance?(name, )) name else #f end; end function; define inline method initialize (f :: , #key) next-method(); fragment-macro(f) := suffix-name-hygienically(fragment-define-word(f), "-definer"); end method; define method fragment-kind (f :: ) => kind; $parsed-macro-call-token; end method; define class () constant slot fragment-body-fragment, required-init-keyword: body-fragment:; constant slot fragment-end-word = #f, init-keyword: end-word:; end class; /* define method initialize (f :: , #key) next-method(); // If it's all potential modifiers in the body until a definition, // then warn. block (return) for (fragment in fragment-list-fragment(f)) if (~instance?(fragment, )) return(); end; select (fragment-kind(fragment)) $define-body-word-only-token, $define-list-word-only-token, $begin-and-define-body-word-token, $begin-and-define-list-word-token, $function-and-define-body-word-token, $function-and-define-list-word-token => signal("Ambiguous stuff - %s vs %s", fragment-define-word(f), fragment); otherwise => #t; end; end; end; end method; */ define class () constant slot fragment-list-fragment, required-init-keyword: list-fragment:; end class; // For reference macros. define method fragment-macro (f :: ) => (f :: ) f end method; //// Extra surface syntax for the macro system. define class () constant slot fragment-macro-body-fragment, required-init-keyword: macro-body-fragment:; constant slot fragment-end-word = #f, init-keyword: end-word:; end class; define abstract class () end class; define method fragment-kind (f :: ) => kind; $escaped-substitution-token end method; define class () constant slot fragment-name :: type-union (, ), required-init-keyword: name:; constant slot fragment-constraint :: false-or(), required-init-keyword: constraint:; end class; define class () constant slot fragment-name :: type-union (, ), required-init-keyword: name:; // slot fragment-constraint :: false-or(), // required-init-keyword: constraint:; constant slot fragment-separator :: false-or(), required-init-keyword: separator:; end class; define class () constant slot fragment-name :: , required-init-keyword: name:; end class; define class () constant slot fragment-prefix, required-init-keyword: prefix:; constant slot fragment-pattern-variable, required-init-keyword: pattern-variable:; constant slot fragment-suffix, required-init-keyword: suffix:; end class; /* define class () constant slot fragment-expression :: , required-init-keyword: name:; end class; define class () slot fragment-expression :: , required-init-keyword: name:; constant slot fragment-separator :: false-or(), required-init-keyword: separator:; end class; */ define abstract class () constant slot fragment-template, required-init-keyword: template:; end class; define class () constant slot fragment-rule-name, required-init-keyword: rule-name:; end class; define class () end class; //// Macro template objects. define class