diff --git a/docs/OPERATORS.md b/docs/OPERATORS.md
index c748fbb..72a1b1e 100644
--- a/docs/OPERATORS.md
+++ b/docs/OPERATORS.md
@@ -27,9 +27,9 @@ This is clearly unacceptable.
> macro definition and make sure those names are looked up in the scope
> of the macro definition instead of the scope where the macro was used.
-This offers hope, if we can re-work the macro system to be hygenic by default,
-then the parser instead of generating
-`addition(a, b)` for `a + b` could instead generate:
+This offers hope, if we can re-work the macro system to be hygenic by
+default, then the parser instead of generating `addition(a, b)` for `a +
+b` could instead generate:
```
macro gensym$1(a, b) { addition(a, b) }
@@ -38,21 +38,23 @@ macro gensym$1(a, b) { addition(a, b) }
at the point of the operator declaration, and generate `gensym$1(a, b)`
when `a + b` is subsequently encountered.
-Firstly I now think the use of a `$` prefix to indicate a gensym in a macro
-is not the best idea. Instead the lambda conversion should identify bound
-`let` variables and replace them automatically. That also frees up `$` as a
-potentially useful user-defined prefix operator.
+Firstly I now think the use of a `$` prefix to indicate a gensym in a
+macro is not the best idea. Instead the lambda conversion should identify
+bound `let` variables and replace them automatically. That also frees up
+`$` as a potentially useful user-defined prefix operator.
-The bigger problem is that we can't continue to do naiive macro expansion during
-the lambda conversion step, or we'd be back where we started with
-`addition(a, b)` referring to whatever `addition` happens to be the current
-definition.
+The bigger problem is that we can't continue to do naiive macro expansion
+during the lambda conversion step, or we'd be back where we started with
+`addition(a, b)` referring to whatever `addition` happens to be the
+current definition.
-We may have to revert to the scheme definition of a macro: pass the arguments
-unevaluated to the macro, evaluate the macro body, then re-evaluate the result.
+We may have to revert to the scheme definition of a macro: pass the
+arguments unevaluated to the macro, evaluate the macro body, then
+re-evaluate the result.
-But we really don't want to have the macro evaluated like that, because F♮ is not
-homoiconic, "evaluating the macro body" can only mean substitution.
+But we really don't want to have the macro evaluated like that,
+because F♮ is not homoiconic, "evaluating the macro body" can only
+mean substitution.
What if the arguments to macros were wrapped in a closure?
@@ -62,16 +64,18 @@ macro AND(a, b) { if (a) { b } else { false } } => fn AND(a, b) { if (a()) { b()
AND(a, b) => AND(fn () { a }, fn () { b })
```
-That would definately work, though it won't be quite as efficient. It solves both
-local scoping rules, since `AND` is now a normal function then free variables in the
-body are evaluated in the context of the function definition, and variables in the
-argument expressions are evaluated in the calling context.
+That would definately work, though it won't be quite as efficient. It
+solves both local scoping rules, since `AND` is now a normal function then
+free variables in the body are evaluated in the context of the function
+definition, and variables in the argument expressions are evaluated in
+the calling context.
-Got that working, and we're also handling local shadowing of arguments so they don't
-get wrapped in an invocation unless they are the same lexical variable.
+> Got that working, and we're also handling local shadowing of arguments
+so they don't get wrapped in an invocation unless they are the same
+lexical variable.
-One little unnecssary inefficiency needs to be addressed. If one macro calls another,
-for example
+One little unnecssary inefficiency needs to be addressed. If one macro
+calls another, for example
```
macro NAND(a, b) { NOT(AND(a, b)) }
@@ -109,6 +113,6 @@ pattern if the argument is being modified, for example if a macro
called another with it's argument modified in some way then the pattern
i.e. `fn() { a() + 1 }` would be necessary.
-Got option 1 working, but no need for extra types, just inspect the
+> Got option 1 working, but no need for extra types, just inspect the
thunk during macro conversion, if it has no arguments and just contains
a symbol that would otherwise be invoked then return the symbol.
diff --git a/docs/generated/ast.md b/docs/generated/ast.md
index a2474a6..f83361f 100644
--- a/docs/generated/ast.md
+++ b/docs/generated/ast.md
@@ -18,8 +18,6 @@ AstDefinitions --definition--> AstDefinition
AstDefinitions --next--> AstDefinitions
AstDefine --symbol--> HashSymbol
AstDefine --expression--> AstExpression
-AstGensymDefine --basename--> HashSymbol
-AstGensymDefine --expression--> AstExpression
AstAlias --name--> HashSymbol
AstAlias --type--> AstType
AstExprAlias --name--> HashSymbol
@@ -89,7 +87,6 @@ AstTypeConstructorArgs --map--> AstTypeMap
AstLookupOrSymbol --symbol--> HashSymbol
AstLookupOrSymbol --lookup--> AstLookupSymbol
AstDefinition --define--> AstDefine
-AstDefinition --gensymDefine--> AstGensymDefine
AstDefinition --typeDef--> AstTypeDef
AstDefinition --macro--> AstDefMacro
AstDefinition --alias--> AstAlias
@@ -114,7 +111,6 @@ AstExpression --alias--> AstExprAlias
AstExpression --funCall--> AstFunCall
AstExpression --lookup--> AstLookup
AstExpression --symbol--> HashSymbol
-AstExpression --gensym--> HashSymbol
AstExpression --number--> MaybeBigInt
AstExpression --character--> character
AstExpression --fun--> AstCompositeFunction
diff --git a/docs/generated/lambda.md b/docs/generated/lambda.md
index d180397..90e92d0 100644
--- a/docs/generated/lambda.md
+++ b/docs/generated/lambda.md
@@ -5,15 +5,12 @@ Plain lambda structures generated by lambda conversion.
```mermaid
flowchart TD
LamMacroTable --entries--> entries
-LamGenSymTable --entries--> entries
+LamMacroArgsTable --entries--> entries
LamInfoTable --entries--> entries
LamAliasTable --entries--> entries
LamExpTable --entries--> entries
LamLam --args--> LamVarList
LamLam --exp--> LamExp
-LamMacro --args--> LamVarList
-LamMacro --exp--> LamExp
-LamMacro --env--> LamContext
LamVarList --var--> HashSymbol
LamVarList --next--> LamVarList
LamPrimApp --type--> LamPrimOp
@@ -74,7 +71,6 @@ LamLetRec --nbindings--> int
LamLetRec --bindings--> LamLetRecBindings
LamLetRec --body--> LamExp
LamLetRecBindings --var--> HashSymbol
-LamLetRecBindings --isGenSym--> bool
LamLetRecBindings --val--> LamExp
LamLetRecBindings --next--> LamLetRecBindings
LamContext --frame--> LamInfoTable
@@ -117,7 +113,6 @@ LamTypeConstructorInfo --index--> int
LamExp --namespaces--> LamNamespaceArray
LamExp --lam--> LamLam
LamExp --var--> HashSymbol
-LamExp --gensym--> HashSymbol
LamExp --stdint--> int
LamExp --biginteger--> MaybeBigInt
LamExp --prim--> LamPrimApp
diff --git a/docs/generated/pratt.md b/docs/generated/pratt.md
index e7b09ea..a77da67 100644
--- a/docs/generated/pratt.md
+++ b/docs/generated/pratt.md
@@ -31,6 +31,7 @@ PrattParser --namespaces--> PrattIntTable
PrattParser --lexer--> PrattLexer
PrattParser --trie--> PrattTrie
PrattParser --panicMode--> bool
+PrattParser --isPreamble--> bool
PrattParser --next--> PrattParser
PrattRecord --symbol--> HashSymbol
PrattRecord --prefixOp--> PrattOp
@@ -50,6 +51,7 @@ PrattNumberState["enum PrattNumberState"]
PrattStringState["enum PrattStringState"]
PrattFixity["enum PrattFixity"]
PrattUTF8["PrattUTF8[]"] --entries--> uchar
+PrattParsers["PrattParsers[]"] --entries--> PrattParser
PrattUnicode["PrattUnicode[]"] --entries--> character
PrattValueVal
PrattValueType
diff --git a/src/lambda_simplfication.c b/src/lambda_simplfication.c
new file mode 100644
index 0000000..025aa9c
--- /dev/null
+++ b/src/lambda_simplfication.c
@@ -0,0 +1,359 @@
+/*
+ * CEKF - VM supporting amb
+ * Copyright (C) 2022-2024 Bill Hails
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+
+#include
+#include
+#include "common.h"
+#include "lambda_simplification.h"
+#include "symbol.h"
+#include "lambda_pp.h"
+#include "lambda_debug.h"
+
+#ifdef DEBUG_LAMBDA_SIMPLIFICATION
+# include "debugging_on.h"
+#else
+# include "debugging_off.h"
+#endif
+
+// fn () { a() } == a
+static LamExp *performLamSimplifications(LamLam *lam) {
+ ENTER(performLamSimplifications);
+ lam->exp = lamPerformSimplifications(lam->exp);
+ if ( lam->args == NULL
+ && lam->exp->type == LAMEXP_TYPE_APPLY
+ && lam->exp->val.apply->args == NULL) {
+ LEAVE(performLamSimplifications);
+ return lam->exp->val.apply->function;
+ }
+ LEAVE(performLamSimplifications);
+ return newLamExp_Lam(CPI(lam), lam);
+}
+
+static HashSymbol *performVarSimplifications(HashSymbol *var) {
+ return var;
+}
+
+static LamPrimApp *performPrimSimplifications(LamPrimApp *prim) {
+ ENTER(performPrimSimplifications);
+ prim->exp1 = lamPerformSimplifications(prim->exp1);
+ prim->exp2 = lamPerformSimplifications(prim->exp2);
+ LEAVE(performPrimSimplifications);
+ return prim;
+}
+
+static LamUnaryApp *performUnarySimplifications(LamUnaryApp *unary) {
+ ENTER(performUnarySimplifications);
+ unary->exp = lamPerformSimplifications(unary->exp);
+ LEAVE(performUnarySimplifications);
+ return unary;
+}
+
+static LamSequence *performSequenceSimplifications(LamSequence *sequence) {
+ ENTER(performSequenceSimplifications);
+ if (sequence == NULL) {
+ LEAVE(performSequenceSimplifications);
+ return NULL;
+ }
+ sequence->next =
+ performSequenceSimplifications(sequence->next);
+ sequence->exp = lamPerformSimplifications(sequence->exp);
+ LEAVE(performSequenceSimplifications);
+ return sequence;
+}
+
+static LamList *performListSimplifications(LamList *list) {
+ ENTER(performListSimplifications);
+ if (list == NULL) {
+ LEAVE(performListSimplifications);
+ return NULL;
+ }
+ list->next = performListSimplifications(list->next);
+ list->exp = lamPerformSimplifications(list->exp);
+ LEAVE(performListSimplifications);
+ return list;
+}
+
+static LamTupleIndex *performTupleIndexSimplifications(LamTupleIndex *tupleIndex) {
+ tupleIndex->exp = lamPerformSimplifications(tupleIndex->exp);
+ return tupleIndex;
+}
+
+static LamPrint *performPrintSimplifications(LamPrint *print) {
+ print->exp = lamPerformSimplifications(print->exp);
+ print->printer = lamPerformSimplifications(print->printer);
+ return print;
+}
+
+static LamLookup *performLookupSimplifications(LamLookup *lookup) {
+ lookup->exp = lamPerformSimplifications(lookup->exp);
+ return lookup;
+}
+
+static LamMakeVec *performMakeVecSimplifications(LamMakeVec *makeVec) {
+ ENTER(performMakeVecSimplifications);
+ makeVec->args = performListSimplifications(makeVec->args);
+ LEAVE(performMakeVecSimplifications);
+ return makeVec;
+}
+
+static LamDeconstruct *performDeconstructSimplifications(LamDeconstruct *deconstruct) {
+ ENTER(performDeconstructSimplifications);
+ deconstruct->exp = lamPerformSimplifications(deconstruct->exp);
+ LEAVE(performDeconstructSimplifications);
+ return deconstruct;
+}
+
+static LamConstruct *performConstructSimplifications(LamConstruct *construct) {
+ ENTER(performConstructSimplifications);
+ construct->args = performListSimplifications(construct->args);
+ LEAVE(performConstructSimplifications);
+ return construct;
+}
+
+static LamApply *performApplySimplifications(LamApply *apply) {
+ ENTER(performApplySimplifications);
+ apply->function = lamPerformSimplifications(apply->function);
+ apply->args = performListSimplifications(apply->args);
+ LEAVE(performApplySimplifications);
+ return apply;
+}
+
+static LamIff *performIffSimplifications(LamIff *iff) {
+ ENTER(performIffSimplifications);
+ iff->condition = lamPerformSimplifications(iff->condition);
+ iff->consequent = lamPerformSimplifications(iff->consequent);
+ iff->alternative = lamPerformSimplifications(iff->alternative);
+ LEAVE(performIffSimplifications);
+ return iff;
+}
+
+static LamLetRecBindings *performBindingsSimplifications(LamLetRecBindings *bindings) {
+ ENTER(performBindingsSimplifications);
+ if (bindings == NULL) {
+ LEAVE(performBindingsSimplifications);
+ return NULL;
+ }
+ bindings->next = performBindingsSimplifications(bindings->next);
+ bindings->val = lamPerformSimplifications(bindings->val);
+ LEAVE(performBindingsSimplifications);
+ return bindings;
+}
+
+static LamLet *performLetSimplifications(LamLet *let) {
+ ENTER(performLetSimplifications);
+ let->value = lamPerformSimplifications(let->value);
+ let->body = lamPerformSimplifications(let->body);
+ LEAVE(performLetSimplifications);
+ return let;
+}
+
+static LamLetRec *performLetRecSimplifications(LamLetRec *letrec) {
+ ENTER(performLetRecSimplifications);
+ letrec->bindings = performBindingsSimplifications(letrec->bindings);
+ letrec->body = lamPerformSimplifications(letrec->body);
+ LEAVE(performLetRecSimplifications);
+ return letrec;
+}
+
+static LamTypeDefs *performTypeDefsSimplifications(LamTypeDefs *typedefs) {
+ ENTER(performTypeDefsSimplifications);
+ typedefs->body = lamPerformSimplifications(typedefs->body);
+ LEAVE(performTypeDefsSimplifications);
+ return typedefs;
+}
+
+static LamMatchList *performCaseSimplifications(LamMatchList *cases) {
+ ENTER(performCaseSimplifications);
+ if (cases == NULL) {
+ LEAVE(performCaseSimplifications);
+ return NULL;
+ }
+ cases->next = performCaseSimplifications(cases->next);
+ cases->body = lamPerformSimplifications(cases->body);
+ LEAVE(performCaseSimplifications);
+ return cases;
+}
+
+static LamMatch *performMatchSimplifications(LamMatch *match) {
+ ENTER(performMatchSimplifications);
+ match->index = lamPerformSimplifications(match->index);
+ match->cases = performCaseSimplifications(match->cases);
+ LEAVE(performMatchSimplifications);
+ return match;
+}
+
+static LamAmb *performAmbSimplifications(LamAmb *amb) {
+ ENTER(performAmbSimplifications);
+ amb->left = lamPerformSimplifications(amb->left);
+ amb->right = lamPerformSimplifications(amb->right);
+ LEAVE(performAmbSimplifications);
+ return amb;
+}
+
+static LamIntCondCases *performIntCondCaseSimplifications(LamIntCondCases *cases) {
+ ENTER(performIntCondCaseSimplifications);
+ if (cases == NULL) {
+ LEAVE(performIntCondCaseSimplifications);
+ return NULL;
+ }
+ cases->body = lamPerformSimplifications(cases->body);
+ cases->next = performIntCondCaseSimplifications(cases->next);
+ LEAVE(performIntCondCaseSimplifications);
+ return cases;
+}
+
+static LamCharCondCases *performCharCondCaseSimplifications(LamCharCondCases *cases) {
+ ENTER(performCharCondCaseSimplifications);
+ if (cases == NULL) {
+ LEAVE(performCharCondCaseSimplifications);
+ return NULL;
+ }
+ cases->body = lamPerformSimplifications(cases->body);
+ cases->next = performCharCondCaseSimplifications(cases->next);
+ LEAVE(performCharCondCaseSimplifications);
+ return cases;
+}
+
+static LamCondCases *performCondCaseSimplifications(LamCondCases *cases) {
+ ENTER(performCondCaseSimplifications);
+ if (cases == NULL) {
+ LEAVE(performCondCaseSimplifications);
+ return NULL;
+ }
+ switch (cases->type) {
+ case LAMCONDCASES_TYPE_INTEGERS:
+ cases->val.integers = performIntCondCaseSimplifications(cases->val.integers);
+ break;
+ case LAMCONDCASES_TYPE_CHARACTERS:
+ cases->val.characters = performCharCondCaseSimplifications(cases->val.characters);
+ break;
+ default:
+ cant_happen("unrecognised %s", lamCondCasesTypeName(cases->type));
+ }
+ LEAVE(performCondCaseSimplifications);
+ return cases;
+}
+
+static LamCond *performCondSimplifications(LamCond *cond) {
+ ENTER(performCondSimplifications);
+ cond->value = lamPerformSimplifications(cond->value);
+ cond->cases = performCondCaseSimplifications(cond->cases);
+ LEAVE(performCondSimplifications);
+ return cond;
+}
+
+static LamNamespaceArray *performNamespacesSimplifications(LamNamespaceArray *namespaces) {
+ for (Index i = 0; i < namespaces->size; i++) {
+ namespaces->entries[i] = lamPerformSimplifications(namespaces->entries[i]);
+ }
+ return namespaces;
+}
+
+LamExp *lamPerformSimplifications(LamExp *exp) {
+ ENTER(lamPerformSimplifications);
+ // ppLamExp(exp);
+ // eprintf("\n");
+ if (exp != NULL) {
+ switch (exp->type) {
+ case LAMEXP_TYPE_BIGINTEGER:
+ case LAMEXP_TYPE_STDINT:
+ case LAMEXP_TYPE_CHARACTER:
+ case LAMEXP_TYPE_BACK:
+ case LAMEXP_TYPE_COND_DEFAULT:
+ case LAMEXP_TYPE_ERROR:
+ case LAMEXP_TYPE_CONSTANT:
+ case LAMEXP_TYPE_CONSTRUCTOR:
+ case LAMEXP_TYPE_ENV:
+ break;
+ case LAMEXP_TYPE_LAM:
+ exp = performLamSimplifications(exp->val.lam);
+ break;
+ case LAMEXP_TYPE_VAR:
+ exp->val.var = performVarSimplifications(exp->val.var);
+ break;
+ case LAMEXP_TYPE_PRIM:
+ exp->val.prim = performPrimSimplifications(exp->val.prim);
+ break;
+ case LAMEXP_TYPE_UNARY:
+ exp->val.unary = performUnarySimplifications(exp->val.unary);
+ break;
+ case LAMEXP_TYPE_LIST:
+ exp->val.list = performSequenceSimplifications(exp->val.list);
+ break;
+ case LAMEXP_TYPE_MAKEVEC:
+ exp->val.makeVec = performMakeVecSimplifications(exp->val.makeVec);
+ break;
+ case LAMEXP_TYPE_DECONSTRUCT:
+ exp->val.deconstruct = performDeconstructSimplifications(exp->val.deconstruct);
+ break;
+ case LAMEXP_TYPE_CONSTRUCT:
+ exp->val.construct = performConstructSimplifications(exp->val.construct);
+ break;
+ case LAMEXP_TYPE_TAG:
+ exp->val.tag = lamPerformSimplifications(exp->val.tag);
+ break;
+ case LAMEXP_TYPE_APPLY:
+ exp->val.apply = performApplySimplifications(exp->val.apply);
+ break;
+ case LAMEXP_TYPE_IFF:
+ exp->val.iff = performIffSimplifications(exp->val.iff);
+ break;
+ case LAMEXP_TYPE_COND:
+ exp->val.cond = performCondSimplifications(exp->val.cond);
+ break;
+ case LAMEXP_TYPE_CALLCC:
+ exp->val.callcc = lamPerformSimplifications(exp->val.callcc);
+ break;
+ case LAMEXP_TYPE_LET:
+ exp->val.let = performLetSimplifications(exp->val.let);
+ break;
+ case LAMEXP_TYPE_LETREC:
+ exp->val.letrec = performLetRecSimplifications(exp->val.letrec);
+ break;
+ case LAMEXP_TYPE_TYPEDEFS:
+ exp->val.typedefs = performTypeDefsSimplifications(exp->val.typedefs);
+ break;
+ case LAMEXP_TYPE_MATCH:
+ exp->val.match = performMatchSimplifications(exp->val.match);
+ break;
+ case LAMEXP_TYPE_AMB:
+ exp->val.amb = performAmbSimplifications(exp->val.amb);
+ break;
+ case LAMEXP_TYPE_MAKE_TUPLE:
+ exp->val.make_tuple = performListSimplifications(exp->val.make_tuple);
+ break;
+ case LAMEXP_TYPE_TUPLE_INDEX:
+ exp->val.tuple_index = performTupleIndexSimplifications(exp->val.tuple_index);
+ break;
+ case LAMEXP_TYPE_PRINT:
+ exp->val.print = performPrintSimplifications(exp->val.print);
+ break;
+ case LAMEXP_TYPE_LOOKUP:
+ exp->val.lookup = performLookupSimplifications(exp->val.lookup);
+ break;
+ case LAMEXP_TYPE_NAMESPACES:
+ exp->val.namespaces = performNamespacesSimplifications(exp->val.namespaces);
+ break;
+ default:
+ cant_happen("unrecognized %s", lamExpTypeName(exp->type));
+ }
+ }
+ LEAVE(lamPerformSimplifications);
+ return exp;
+}
diff --git a/src/lambda_simplification.h b/src/lambda_simplification.h
new file mode 100644
index 0000000..2136266
--- /dev/null
+++ b/src/lambda_simplification.h
@@ -0,0 +1,25 @@
+#ifndef cekf_lambda_simplification_h
+# define cekf_lambda_simplification_h
+/*
+ * CEKF - VM supporting amb
+ * Copyright (C) 2022-2024 Bill Hails
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "lambda.h"
+
+LamExp *lamPerformSimplifications(LamExp *);
+
+#endif
diff --git a/src/main.c b/src/main.c
index 88cb877..93b8f63 100644
--- a/src/main.c
+++ b/src/main.c
@@ -27,6 +27,7 @@
#include "ast_debug.h"
#include "lambda_debug.h"
#include "lambda_conversion.h"
+#include "lambda_simplification.h"
#include "annotate.h"
#include "anf.h"
#include "anf_normalize.h"
@@ -232,6 +233,8 @@ static LamExp *convertProg(AstProg *prog) {
if (hadErrors()) {
exit(1);
}
+ exp = lamPerformSimplifications(exp);
+ REPLACE_PROTECT(save, exp);
if (lambda_flag) {
ppLamExp(exp);
eprintf("\n");