From 4c973195c9fd1a0a6d01915518be584be3377814 Mon Sep 17 00:00:00 2001 From: Bill Hails Date: Fri, 1 Mar 2024 17:42:10 +0000 Subject: [PATCH 01/33] indent --- Makefile | 2 +- src/bigint.c | 6 +++--- src/bigint.h | 6 +++--- src/module.c | 6 +++--- src/module.h | 6 +++--- src/tc_analyze.c | 4 +--- src/tpmc_logic.c | 8 ++++---- src/tpmc_match.c | 9 +++++---- 8 files changed, 23 insertions(+), 24 deletions(-) diff --git a/Makefile b/Makefile index fe4acc7..6bf1e7e 100644 --- a/Makefile +++ b/Makefile @@ -138,7 +138,7 @@ profile: all valgrind --tool=callgrind ./$(TARGET) indent: .typedefs - (cd src; indent `cat ../.typedefs | sort -u | xargs` -T bigint_word -T BigInt -T IntegerBinOp -T Control -T Stack -T Env -T Snapshot -T Kont -T ValueList -T Clo -T Fail -T Vec -T ProtectionStack -T HashSymbol -T hash_t -T Header -T PmModule -T HashTable -T byte -T word -T ByteCodes -T ByteCodeArray -T Value *.[ch]) + (cd src; indent `cat ../.typedefs | sort -u | xargs` -T bigint_word -T BigInt -T IntegerBinOp -T Control -T Stack -T Env -T Snapshot -T Kont -T ValueList -T Clo -T Fail -T Vec -T ProtectionStack -T HashSymbol -T hash_t -T Header -T PmModule -T HashTable -T byte -T word -T ByteCodes -T ByteCodeArray -T Value -T FILE *.[ch]) .typedefs: .generated diff --git a/src/bigint.c b/src/bigint.c index a80672a..b9b1fed 100644 --- a/src/bigint.c +++ b/src/bigint.c @@ -1304,7 +1304,7 @@ void printBigInt(BigInt *x, int depth) { fprintBigInt(stderr, x); } -void bigint_fprint(FILE * f, bigint * bi) { +void bigint_fprint(FILE *f, bigint * bi) { int size = bigint_write_size(bi, 10); if (size < 256) { static char buffer[256]; @@ -1318,7 +1318,7 @@ void bigint_fprint(FILE * f, bigint * bi) { } } -void fprintBigInt(FILE * f, BigInt *x) { +void fprintBigInt(FILE *f, BigInt *x) { if (x == NULL) { fprintf(f, ""); return; @@ -1394,7 +1394,7 @@ BigInt *powBigInt(BigInt *a, BigInt *b) { return res; } -void dumpBigInt(FILE * fp, BigInt *big) { +void dumpBigInt(FILE *fp, BigInt *big) { fprintf(fp, "BigInt %p", big); if (big != NULL) { fprintf(fp, " size:%d, capacity:%d, neg:%d, words:[", big->bi.size, diff --git a/src/bigint.h b/src/bigint.h index 998204d..32c8ca1 100644 --- a/src/bigint.h +++ b/src/bigint.h @@ -53,10 +53,10 @@ extern "C" { void markBigInt(BigInt *bi); void freeBigInt(BigInt *bi); void printBigInt(BigInt *bi, int depth); - void fprintBigInt(FILE * f, BigInt *x); + void fprintBigInt(FILE *f, BigInt *x); void sprintBigInt(char *s, BigInt *x); int cmpBigInt(BigInt *a, BigInt *b); - void dumpBigInt(FILE * fp, BigInt *big); + void dumpBigInt(FILE *fp, BigInt *big); typedef bigint *(*bigint_binop)(bigint * dst, const bigint * a, const bigint * b); BigInt *addBigInt(BigInt *a, BigInt *b); @@ -65,7 +65,7 @@ extern "C" { BigInt *divBigInt(BigInt *a, BigInt *b); BigInt *modBigInt(BigInt *a, BigInt *b); BigInt *powBigInt(BigInt *a, BigInt *b); - void bigint_fprint(FILE * f, bigint * bi); + void bigint_fprint(FILE *f, bigint * bi); // END CEKF additions diff --git a/src/module.c b/src/module.c index cc5915e..7bbf79d 100644 --- a/src/module.c +++ b/src/module.c @@ -55,7 +55,7 @@ static FILE *safeFOpen(const char *filename) { return f; } -PmModule *newPmModuleFromFileHandle(FILE * f, const char *origin) { +PmModule *newPmModuleFromFileHandle(FILE *f, const char *origin) { PmModule *mod = newPmModule(); int save = PROTECT(mod); YY_BUFFER_STATE bs = yy_create_buffer(f, YY_BUF_SIZE, mod->scanner); @@ -90,7 +90,7 @@ static void pushPmToplevelFromBufState(PmModule *mod, YY_BUFFER_STATE bs, UNPROTECT(save); } -PmModule *newPmToplevelFromFileHandle(FILE * f, const char *origin) { +PmModule *newPmToplevelFromFileHandle(FILE *f, const char *origin) { PmModule *mod = newPmModule(); pushPmToplevelFromBufState(mod, yy_create_buffer(f, YY_BUF_SIZE, mod->scanner), @@ -171,7 +171,7 @@ void incLineNo(PmModule *mod) { mod->bufStack->lineno++; } -void showModuleState(FILE * fp, PmModule *mod) { +void showModuleState(FILE *fp, PmModule *mod) { if (mod == NULL) { fprintf(fp, "module is null\n"); return; diff --git a/src/module.h b/src/module.h index ac6b50f..778f07a 100644 --- a/src/module.h +++ b/src/module.h @@ -12,12 +12,12 @@ typedef struct PmModule { AstNest *nest; } PmModule; -PmModule *newPmModuleFromFileHandle(FILE * f, const char *origin); +PmModule *newPmModuleFromFileHandle(FILE *f, const char *origin); PmModule *newPmModuleFromStdin(void); PmModule *newPmModuleFromFile(const char *filename); PmModule *newPmModuleFromString(char *src, char *id); -PmModule *newPmToplevelFromFileHandle(FILE * f, const char *origin); +PmModule *newPmToplevelFromFileHandle(FILE *f, const char *origin); PmModule *newPmToplevelFromStdin(void); PmModule *newPmToplevelFromFile(const char *filename); PmModule *newPmToplevelFromString(char *src, char *id); @@ -27,6 +27,6 @@ void freePmModule(Header *h); int pmParseModule(PmModule *mod); void incLineNo(PmModule *mod); int popPmFile(PmModule *mod); -void showModuleState(FILE * fp, PmModule *mod); +void showModuleState(FILE *fp, PmModule *mod); #endif diff --git a/src/tc_analyze.c b/src/tc_analyze.c index c13ed7f..bd32d4b 100644 --- a/src/tc_analyze.c +++ b/src/tc_analyze.c @@ -1537,9 +1537,7 @@ static bool unify(TcType *a, TcType *b) { a = prune(a); b = prune(b); DEBUG("UNIFY"); - IFDEBUG(ppTcType(a); - eprintf(" WITH "); - ppTcType(b)); + IFDEBUG(ppTcType(a); eprintf(" WITH "); ppTcType(b)); if (a == b) return true; if (a->type == TCTYPE_TYPE_VAR) { diff --git a/src/tpmc_logic.c b/src/tpmc_logic.c index 9c0b819..d263a26 100644 --- a/src/tpmc_logic.c +++ b/src/tpmc_logic.c @@ -405,8 +405,8 @@ static TpmcPattern *collectAssignmentSubstitutions(TpmcPattern *pattern, TpmcSub pattern->pattern->val.assignment->name, pattern->path); // we no longer need to remember this is an assignment now we have the substitution - return collectPatternSubstitutions(pattern->pattern->val.assignment-> - value, substitutions); + return collectPatternSubstitutions(pattern->pattern->val. + assignment->value, substitutions); } static TpmcPattern *collectConstructorSubstitutions(TpmcPattern *pattern, TpmcSubstitutionTable @@ -424,8 +424,8 @@ static TpmcPattern *collectConstructorSubstitutions(TpmcPattern *pattern, TpmcSu static TpmcPattern *collectComparisonSubstitutions(TpmcPattern *pattern, TpmcSubstitutionTable *substitutions) { pattern->pattern->val.comparison->previous = - collectPatternSubstitutions(pattern->pattern->val.comparison-> - previous, substitutions); + collectPatternSubstitutions(pattern->pattern->val. + comparison->previous, substitutions); pattern->pattern->val.comparison->current = collectPatternSubstitutions(pattern->pattern->val.comparison->current, substitutions); diff --git a/src/tpmc_match.c b/src/tpmc_match.c index c636404..f8878f3 100644 --- a/src/tpmc_match.c +++ b/src/tpmc_match.c @@ -268,8 +268,8 @@ static void populateSubPatternMatrixRowWithComponents(TpmcMatrix *matrix, } for (int i = 0; i < arity; i++) { setTpmcMatrixIndex(matrix, i, y, - pattern->pattern->val.constructor->components-> - entries[i]); + pattern->pattern->val.constructor-> + components->entries[i]); } LEAVE(populateSubPatternMatrixRowWithComponents); } @@ -511,8 +511,9 @@ static void collectPathsBoundByPattern(TpmcPattern *pattern, case TPMCPATTERNVALUE_TYPE_BIGINTEGER: break; case TPMCPATTERNVALUE_TYPE_CONSTRUCTOR: - collectPathsBoundByConstructor(pattern->pattern->val.constructor-> - components, boundVariables); + collectPathsBoundByConstructor(pattern->pattern->val. + constructor->components, + boundVariables); break; default: cant_happen("unrecognised type %d in collectPathsBoundByPattern", From cbd9149bcdabfd192b194d78a67dfbdaa30d5d28 Mon Sep 17 00:00:00 2001 From: Bill Hails Date: Fri, 1 Mar 2024 17:52:02 +0000 Subject: [PATCH 02/33] renamed flat type to user type --- src/ast.yaml | 21 ++----------------- src/lambda_conversion.c | 8 +++---- src/parser.y | 46 +++++------------------------------------ 3 files changed, 11 insertions(+), 64 deletions(-) diff --git a/src/ast.yaml b/src/ast.yaml index c121030..ed9b28e 100644 --- a/src/ast.yaml +++ b/src/ast.yaml @@ -36,27 +36,15 @@ structs: symbol: HashSymbol expression: AstExpression - AstPrototype: - symbol: HashSymbol - body: AstPrototypeBody - - AstPrototypeBody: - single: AstSinglePrototype - next: AstPrototypeBody - - AstPrototypeSymbolType: - symbol: HashSymbol - type: AstType - AstLoad: package: AstPackage symbol: HashSymbol AstTypeDef: - flatType: AstFlatType + userType: AstUserType typeBody: AstTypeBody - AstFlatType: + AstUserType: symbol: HashSymbol typeSymbols: AstTypeSymbols @@ -143,14 +131,9 @@ structs: unions: AstDefinition: define: AstDefine - prototype: AstPrototype load: AstLoad typeDef: AstTypeDef - AstSinglePrototype: - symbolType: AstPrototypeSymbolType - prototype: AstPrototype - AstTypeClause: integer: void_ptr character: void_ptr diff --git a/src/lambda_conversion.c b/src/lambda_conversion.c index aa55ac3..c42253b 100644 --- a/src/lambda_conversion.c +++ b/src/lambda_conversion.c @@ -187,10 +187,10 @@ static LamTypeArgs *convertTypeSymbols(AstTypeSymbols *symbols) { return this; } -static LamType *convertTypeDefType(AstFlatType *flat) { - LamTypeArgs *args = convertTypeSymbols(flat->typeSymbols); +static LamType *convertTypeDefType(AstUserType *userType) { + LamTypeArgs *args = convertTypeSymbols(userType->typeSymbols); int save = PROTECT(args); - LamType *res = newLamType(flat->symbol, args); + LamType *res = newLamType(userType->symbol, args); UNPROTECT(save); return res; } @@ -323,7 +323,7 @@ static LamTypeConstructor *collectTypeConstructor(AstTypeConstructor } static LamTypeDef *collectTypeDef(AstTypeDef *typeDef, LamContext *env) { - LamType *type = convertTypeDefType(typeDef->flatType); + LamType *type = convertTypeDefType(typeDef->userType); int save = PROTECT(type); AstTypeBody *typeBody = typeDef->typeBody; bool hasFields = typeHasFields(typeBody); diff --git a/src/parser.y b/src/parser.y index 8d840c3..e1e4c5c 100644 --- a/src/parser.y +++ b/src/parser.y @@ -130,17 +130,13 @@ static AstCompositeFunction *makeAstCompositeFunction(AstAltFunction *functions, AstEnvType *envType; AstExpression *expression; AstExpressions *expressions; - AstFlatType *flatType; + AstUserType *userType; AstFunCall *funCall; AstLoad *load; AstNamedArg *namedArg; AstNest *nest; AstPackage *package; AstPrint *print; - AstPrototypeBody *prototypeBody; - AstPrototype *prototype; - AstPrototypeSymbolType *prototypeSymbolType; - AstSinglePrototype *singlePrototype; HashSymbol *symbol; AstTypeBody *typeBody; AstTypeClause *typeClause; @@ -169,17 +165,13 @@ static AstCompositeFunction *makeAstCompositeFunction(AstAltFunction *functions, %type env_type %type expression %type expressions expression_statements -%type flat_type +%type user_type %type fun_call binop conslist unop switch string %type load %type named_farg %type top nest nest_body iff_nest %type package extends %type print -%type prototype_body -%type prototype_symbol_type -%type prototype -%type single_prototype %type symbol type_symbol as %type type_body %type type_clause @@ -260,43 +252,15 @@ definitions : %empty { $$ = NULL; } ; definition : symbol '=' expression ';' { $$ = newAstDefinition( AST_DEFINITION_TYPE_DEFINE, AST_DEFINITION_VAL_DEFINE(newAstDefine($1, $3))); } - | prototype { $$ = newAstDefinition( AST_DEFINITION_TYPE_PROTOTYPE, AST_DEFINITION_VAL_PROTOTYPE($1)); } | load { $$ = newAstDefinition( AST_DEFINITION_TYPE_LOAD, AST_DEFINITION_VAL_LOAD($1)); } | typedef { $$ = newAstDefinition( AST_DEFINITION_TYPE_TYPEDEF, AST_DEFINITION_VAL_TYPEDEF($1)); } | defun { $$ = newAstDefinition( AST_DEFINITION_TYPE_DEFINE, AST_DEFINITION_VAL_DEFINE($1)); } | denv { $$ = newAstDefinition( AST_DEFINITION_TYPE_DEFINE, AST_DEFINITION_VAL_DEFINE($1)); } ; -prototype : PROTOTYPE symbol '{' prototype_body '}' { $$ = newAstPrototype($2, $4); } - ; - defun : FN symbol fun { $$ = newAstDefine($2, newAstExpression(AST_EXPRESSION_TYPE_FUN, AST_EXPRESSION_VAL_FUN($3))); } ; -prototype_body : %empty { $$ = NULL; } - | single_prototype prototype_body { - if ($2 == NULL) $$ = newAstPrototypeBody($1, NULL); - else $$ = newAstPrototypeBody($1, $2); - } - ; - -single_prototype : prototype_symbol_type ';' { - $$ = newAstSinglePrototype( - AST_SINGLEPROTOTYPE_TYPE_SYMBOLTYPE, - AST_SINGLEPROTOTYPE_VAL_SYMBOLTYPE($1) - ); - } - | prototype { - $$ = newAstSinglePrototype( - AST_SINGLEPROTOTYPE_TYPE_PROTOTYPE, - AST_SINGLEPROTOTYPE_VAL_PROTOTYPE($1) - ); - } - ; - -prototype_symbol_type : symbol ':' type { $$ = newAstPrototypeSymbolType($1, $3); } - ; - denv : ENV symbol env_expr { $$ = newAstDefine($2, newAstExpression(AST_EXPRESSION_TYPE_ENV, AST_EXPRESSION_VAL_ENV($3))); } ; @@ -309,11 +273,11 @@ as : %empty { $$ = NULL; } /******************************** types */ -typedef : TYPEDEF flat_type '{' type_body '}' { $$ = newAstTypeDef($2, $4); } +typedef : TYPEDEF user_type '{' type_body '}' { $$ = newAstTypeDef($2, $4); } ; -flat_type : symbol { $$ = newAstFlatType($1, NULL); } - | symbol '(' type_symbols ')' { $$ = newAstFlatType($1, $3); } +user_type : symbol { $$ = newAstUserType($1, NULL); } + | symbol '(' type_symbols ')' { $$ = newAstUserType($1, $3); } ; type_symbols : type_symbol { $$ = newAstTypeSymbols($1, NULL); } From 2217b60f855293efbfbece7a74cdc2e43fc4437d Mon Sep 17 00:00:00 2001 From: Bill Hails Date: Fri, 1 Mar 2024 18:13:32 +0000 Subject: [PATCH 03/33] continued renaming flat to user --- README.md | 10 +++++----- src/lambda_conversion.c | 4 ++-- src/tc_analyze.c | 4 +++- src/tpmc_logic.c | 8 ++++---- src/tpmc_match.c | 9 ++++----- 5 files changed, 18 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index faddb8a..677c523 100644 --- a/README.md +++ b/README.md @@ -69,12 +69,12 @@ the $step$ function: one to deal with `amb` and one to deal with `back`. flowchart TD source --> -AST[Parser] --abstract syntax--> -lambda[Lambda Conversion] --lambda calculus--> +AST[Parser] --abstract syntax--> +lambda[Lambda Conversion] --lambda calculus--> check[Type Checking] --typed lambda calculus--> -anf[A-Normal Form Conversion] --ANF--> -desugaring2[Desugaring] --ANF--> -static[Static Analysis] --annotated ANF--> +anf[A-Normal Form Conversion] --ANF--> +desugaring[Desugaring] --ANF--> +static[Static Analysis] --annotated ANF--> Bytecode[Bytecode Generation] --bytecode--> VM ``` diff --git a/src/lambda_conversion.c b/src/lambda_conversion.c index c42253b..23ce2e8 100644 --- a/src/lambda_conversion.c +++ b/src/lambda_conversion.c @@ -187,7 +187,7 @@ static LamTypeArgs *convertTypeSymbols(AstTypeSymbols *symbols) { return this; } -static LamType *convertTypeDefType(AstUserType *userType) { +static LamType *convertUserType(AstUserType *userType) { LamTypeArgs *args = convertTypeSymbols(userType->typeSymbols); int save = PROTECT(args); LamType *res = newLamType(userType->symbol, args); @@ -323,7 +323,7 @@ static LamTypeConstructor *collectTypeConstructor(AstTypeConstructor } static LamTypeDef *collectTypeDef(AstTypeDef *typeDef, LamContext *env) { - LamType *type = convertTypeDefType(typeDef->userType); + LamType *type = convertUserType(typeDef->userType); int save = PROTECT(type); AstTypeBody *typeBody = typeDef->typeBody; bool hasFields = typeHasFields(typeBody); diff --git a/src/tc_analyze.c b/src/tc_analyze.c index bd32d4b..c13ed7f 100644 --- a/src/tc_analyze.c +++ b/src/tc_analyze.c @@ -1537,7 +1537,9 @@ static bool unify(TcType *a, TcType *b) { a = prune(a); b = prune(b); DEBUG("UNIFY"); - IFDEBUG(ppTcType(a); eprintf(" WITH "); ppTcType(b)); + IFDEBUG(ppTcType(a); + eprintf(" WITH "); + ppTcType(b)); if (a == b) return true; if (a->type == TCTYPE_TYPE_VAR) { diff --git a/src/tpmc_logic.c b/src/tpmc_logic.c index d263a26..9c0b819 100644 --- a/src/tpmc_logic.c +++ b/src/tpmc_logic.c @@ -405,8 +405,8 @@ static TpmcPattern *collectAssignmentSubstitutions(TpmcPattern *pattern, TpmcSub pattern->pattern->val.assignment->name, pattern->path); // we no longer need to remember this is an assignment now we have the substitution - return collectPatternSubstitutions(pattern->pattern->val. - assignment->value, substitutions); + return collectPatternSubstitutions(pattern->pattern->val.assignment-> + value, substitutions); } static TpmcPattern *collectConstructorSubstitutions(TpmcPattern *pattern, TpmcSubstitutionTable @@ -424,8 +424,8 @@ static TpmcPattern *collectConstructorSubstitutions(TpmcPattern *pattern, TpmcSu static TpmcPattern *collectComparisonSubstitutions(TpmcPattern *pattern, TpmcSubstitutionTable *substitutions) { pattern->pattern->val.comparison->previous = - collectPatternSubstitutions(pattern->pattern->val. - comparison->previous, substitutions); + collectPatternSubstitutions(pattern->pattern->val.comparison-> + previous, substitutions); pattern->pattern->val.comparison->current = collectPatternSubstitutions(pattern->pattern->val.comparison->current, substitutions); diff --git a/src/tpmc_match.c b/src/tpmc_match.c index f8878f3..c636404 100644 --- a/src/tpmc_match.c +++ b/src/tpmc_match.c @@ -268,8 +268,8 @@ static void populateSubPatternMatrixRowWithComponents(TpmcMatrix *matrix, } for (int i = 0; i < arity; i++) { setTpmcMatrixIndex(matrix, i, y, - pattern->pattern->val.constructor-> - components->entries[i]); + pattern->pattern->val.constructor->components-> + entries[i]); } LEAVE(populateSubPatternMatrixRowWithComponents); } @@ -511,9 +511,8 @@ static void collectPathsBoundByPattern(TpmcPattern *pattern, case TPMCPATTERNVALUE_TYPE_BIGINTEGER: break; case TPMCPATTERNVALUE_TYPE_CONSTRUCTOR: - collectPathsBoundByConstructor(pattern->pattern->val. - constructor->components, - boundVariables); + collectPathsBoundByConstructor(pattern->pattern->val.constructor-> + components, boundVariables); break; default: cant_happen("unrecognised type %d in collectPathsBoundByPattern", From eb014e2b4516da4cd49e5f50f14b7de1146576d8 Mon Sep 17 00:00:00 2001 From: Bill Hails Date: Sat, 2 Mar 2024 12:21:24 +0000 Subject: [PATCH 04/33] renamed LamTypeConstructorInfo.vec to .needsVec --- src/lambda.yaml | 2 +- src/lambda_conversion.c | 4 ++-- src/print_generator.c | 2 +- src/tpmc_translate.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lambda.yaml b/src/lambda.yaml index e5def85..07da539 100644 --- a/src/lambda.yaml +++ b/src/lambda.yaml @@ -186,7 +186,7 @@ structs: LamTypeConstructorInfo: type: LamTypeConstructor - vec: bool # does this need to be a vector? + needsVec: bool # does this need to be a vector? arity: int # number of arguments to this constructor size: int # number of alternatives index: int # index into list of alternatives diff --git a/src/lambda_conversion.c b/src/lambda_conversion.c index 23ce2e8..97f9300 100644 --- a/src/lambda_conversion.c +++ b/src/lambda_conversion.c @@ -595,7 +595,7 @@ static LamExp *convertFunCall(AstFunCall *funCall, LamContext *env) { } else { LamTypeConstructorInfo *info = lookupInLamContext(env, symbol); if (info != NULL) { - if (info->vec) { + if (info->needsVec) { if (actualNargs == info->arity) { LamExp *inLine = makeConstruct(symbol, info->index, args); @@ -674,7 +674,7 @@ static LamExp *convertSymbol(HashSymbol *symbol, LamContext *env) { return res; } DEBUG("convertSymbol %s is a constructor", symbol->name); - if (info->vec) { + if (info->needsVec) { if (info->arity > 0) { cant_happen("too few arguments to constructor %s", symbol->name); } diff --git a/src/print_generator.c b/src/print_generator.c index aa97e11..88b44c9 100644 --- a/src/print_generator.c +++ b/src/print_generator.c @@ -422,7 +422,7 @@ static LamExp *makeFunctionBody(LamTypeConstructorList *constructors, constructors->constructor->name->name); } LamMatch *match = NULL; - if (info->vec) { + if (info->needsVec) { match = makeTagMatch(constructors, env); } else { match = makePlainMatch(constructors, env); diff --git a/src/tpmc_translate.c b/src/tpmc_translate.c index 3655b9a..9fe3680 100644 --- a/src/tpmc_translate.c +++ b/src/tpmc_translate.c @@ -424,7 +424,7 @@ static LamExp *translateArcList(TpmcArcList *arcList, LamExp *testVar, lambdaCache); PROTECT(matches); LamExp *testExp = NULL; - if (info->vec) { + if (info->needsVec) { testExp = newLamExp(LAMEXP_TYPE_TAG, LAMEXP_VAL_TAG(testVar)); PROTECT(testExp); From 35639b0756792a660708409af8f35c544af5709e Mon Sep 17 00:00:00 2001 From: Bill Hails Date: Sat, 2 Mar 2024 13:10:26 +0000 Subject: [PATCH 05/33] added yaml support for !include and factored out common primitives --- Makefile | 10 +++++----- src/anf.yaml | 29 +++------------------------- src/ast.yaml | 21 +-------------------- src/lambda.yaml | 34 +++++---------------------------- src/primitives.yaml | 38 +++++++++++++++++++++++++++++++++++++ src/tc.yaml | 14 +------------- src/tc_analyze.c | 4 +--- src/tpmc.yaml | 46 ++------------------------------------------- src/tpmc_logic.c | 8 ++++---- src/tpmc_match.c | 9 +++++---- tools/makeAST.py | 24 ++++++++++++++++++++++- 11 files changed, 88 insertions(+), 149 deletions(-) create mode 100644 src/primitives.yaml diff --git a/Makefile b/Makefile index 6bf1e7e..d1ac36c 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ CC=cc -Wall -Wextra -Werror $(CCMODE) LAXCC=cc -Werror $(CCMODE) PYTHON=python3 -EXTRA_YAML=$(wildcard src/*.yaml) +EXTRA_YAML=$(filter-out src/primitives.yaml, $(wildcard src/*.yaml)) EXTRA_C_TARGETS=$(patsubst src/%.yaml,generated/%.c,$(EXTRA_YAML)) EXTRA_H_TARGETS=$(patsubst src/%.yaml,generated/%.h,$(EXTRA_YAML)) EXTRA_OBJTYPES_H_TARGETS=$(patsubst src/%.yaml,generated/%_objtypes.h,$(EXTRA_YAML)) @@ -67,19 +67,19 @@ $(TARGET): $(MAIN_OBJ) $(ALL_OBJ) include $(ALL_DEP) -$(EXTRA_C_TARGETS): generated/%.c: src/%.yaml tools/makeAST.py | generated +$(EXTRA_C_TARGETS): generated/%.c: src/%.yaml tools/makeAST.py src/primitives.yaml | generated $(PYTHON) tools/makeAST.py $< c > $@ || (rm -f $@ ; exit 1) $(EXTRA_H_TARGETS): generated/%.h: src/%.yaml tools/makeAST.py | generated $(PYTHON) tools/makeAST.py $< h > $@ || (rm -f $@ ; exit 1) -$(EXTRA_OBJTYPES_H_TARGETS): generated/%_objtypes.h: src/%.yaml tools/makeAST.py | generated +$(EXTRA_OBJTYPES_H_TARGETS): generated/%_objtypes.h: src/%.yaml tools/makeAST.py src/primitives.yaml | generated $(PYTHON) tools/makeAST.py $< objtypes_h > $@ || (rm -f $@ ; exit 1) -$(EXTRA_DEBUG_H_TARGETS): generated/%_debug.h: src/%.yaml tools/makeAST.py | generated +$(EXTRA_DEBUG_H_TARGETS): generated/%_debug.h: src/%.yaml tools/makeAST.py src/primitives.yaml | generated $(PYTHON) tools/makeAST.py $< debug_h > $@ || (rm -f $@ ; exit 1) -$(EXTRA_DEBUG_C_TARGETS): generated/%_debug.c: src/%.yaml tools/makeAST.py | generated +$(EXTRA_DEBUG_C_TARGETS): generated/%_debug.c: src/%.yaml tools/makeAST.py src/primitives.yaml | generated $(PYTHON) tools/makeAST.py $< debug_c > $@ || (rm -f $@ ; exit 1) .generated: $(EXTRA_TARGETS) $(TMP_H) diff --git a/src/anf.yaml b/src/anf.yaml index e389694..27f8954 100644 --- a/src/anf.yaml +++ b/src/anf.yaml @@ -205,32 +205,9 @@ hashes: CTIntTable: entries: int -primitives: - HashSymbol: - cname: "HashSymbol *" - printFn: "printAstSymbol" - valued: true - bool: - cname: "bool" - printf: "%d" - valued: true - char: - cname: "char" - printf: "%c" - valued: true - int: - cname: "int" - printf: "%d" - valued: true - void_ptr: - cname: "void *" - printf: "%p" - valued: false - BigInt: - cname: "BigInt *" - printFn: "printBigInt" - markFn: "markBigInt" - valued: true +primitives: !include primitives.yaml + +external: TcType: cname: "struct TcType *" printFn: printTcType diff --git a/src/ast.yaml b/src/ast.yaml index ed9b28e..bd24338 100644 --- a/src/ast.yaml +++ b/src/ast.yaml @@ -166,23 +166,4 @@ arrays: dimension: 1 entries: char -enums: {} - -primitives: - HashSymbol: - cname: "HashSymbol *" - printFn: printAstSymbol - valued: true - char: - cname: char - printf: "%c" - valued: true - void_ptr: - cname: "void *" - printf: "%p" - valued: false - BigInt: - cname: "BigInt *" - printFn: printBigInt - markFn: markBigInt - valued: true +primitives: !include primitives.yaml diff --git a/src/lambda.yaml b/src/lambda.yaml index 07da539..c2f8ac6 100644 --- a/src/lambda.yaml +++ b/src/lambda.yaml @@ -90,7 +90,7 @@ structs: next: LamIntCondCases LamCharCondCases: - constant: character + constant: char body: LamExp next: LamCharCondCases @@ -242,7 +242,7 @@ unions: or: LamOr amb: LamAmb print: LamPrint - character: character + character: char back: void_ptr error: void_ptr cond_default: void_ptr @@ -264,35 +264,11 @@ hashes: LamExpTable: entries: LamExp -primitives: - HashSymbol: - cname: "HashSymbol *" - printFn: "printLambdaSymbol" - markFn: "markHashSymbol" - valued: true - BigInt: - cname: "BigInt *" - printFn: "printBigInt" - markFn: "markBigInt" - valued: true +primitives: !include primitives.yaml + +external: TcType: cname: "struct TcType *" printFn: printTcType markFn: markTcType valued: true - void_ptr: - cname: "void *" - printf: "%p" - valued: false - int: - cname: "int" - printf: "%d" - valued: true - bool: - cname: "bool" - printf: "%d" - valued: true - character: - cname: "char" - printf: "%c" - valued: true diff --git a/src/primitives.yaml b/src/primitives.yaml new file mode 100644 index 0000000..b81b57d --- /dev/null +++ b/src/primitives.yaml @@ -0,0 +1,38 @@ +# common primitive types not defined by the schemas + +HashSymbol: + cname: "HashSymbol *" + printFn: printAstSymbol + valued: true + +int: + cname: int + printf: "%d" + valued: true + +void_ptr: + cname: "void *" + printf: "%p" + valued: false + +bool: + cname: "bool" + printf: "%d" + valued: true + +char: + cname: "char" + printf: "%c" + valued: true + +BigInt: + cname: "BigInt *" + printFn: "printBigInt" + markFn: "markBigInt" + valued: true + +string: + cname: "char *" + printf: "%s" + valued: true + diff --git a/src/tc.yaml b/src/tc.yaml index ffad8d1..76a9191 100644 --- a/src/tc.yaml +++ b/src/tc.yaml @@ -71,16 +71,4 @@ unions: character: void_ptr typeDef: TcTypeDef -primitives: - HashSymbol: - cname: "HashSymbol *" - printFn: printAstSymbol - valued: true - int: - cname: int - printf: "%d" - valued: true - void_ptr: - cname: "void *" - printf: "%p" - valued: false +primitives: !include primitives.yaml diff --git a/src/tc_analyze.c b/src/tc_analyze.c index c13ed7f..bd32d4b 100644 --- a/src/tc_analyze.c +++ b/src/tc_analyze.c @@ -1537,9 +1537,7 @@ static bool unify(TcType *a, TcType *b) { a = prune(a); b = prune(b); DEBUG("UNIFY"); - IFDEBUG(ppTcType(a); - eprintf(" WITH "); - ppTcType(b)); + IFDEBUG(ppTcType(a); eprintf(" WITH "); ppTcType(b)); if (a == b) return true; if (a->type == TCTYPE_TYPE_VAR) { diff --git a/src/tpmc.yaml b/src/tpmc.yaml index 5117e41..107dde7 100644 --- a/src/tpmc.yaml +++ b/src/tpmc.yaml @@ -135,21 +135,9 @@ arrays: dimension: 2 entries: TpmcPattern -enums: {} - -primitives: - HashTable: - cname: "HashTable *" - printFn: "printHashTable" - markFn: "markHashTable" - valued: true - - HashSymbol: - cname: "HashSymbol *" - printFn: "printAstSymbol" - markFn: "markHashSymbol" - valued: true +primitives: !include primitives.yaml +external: LamExp: cname: "LamExp *" printFn: ppLamExpD @@ -157,12 +145,6 @@ primitives: copyFn: copyLamExp valued: true - BigInt: - cname: "BigInt *" - printFn: "printBigInt" - markFn: "markBigInt" - valued: true - LamTypeConstructorInfo: cname: "LamTypeConstructorInfo *" printFn: printLamTypeConstructorInfo @@ -170,27 +152,3 @@ primitives: copyFn: copyLamTypeConstructorInfo valued: true - int: - cname: "int" - printf: "%d" - valued: true - - bool: - cname: bool - printf: "%d" - valued: true - - string: - cname: "char *" - printf: "%s" - valued: true - - char: - cname: "char" - printf: "'%c'" - valued: true - - void_ptr: - cname: "void *" - printf: "%p" - valued: false diff --git a/src/tpmc_logic.c b/src/tpmc_logic.c index 9c0b819..d263a26 100644 --- a/src/tpmc_logic.c +++ b/src/tpmc_logic.c @@ -405,8 +405,8 @@ static TpmcPattern *collectAssignmentSubstitutions(TpmcPattern *pattern, TpmcSub pattern->pattern->val.assignment->name, pattern->path); // we no longer need to remember this is an assignment now we have the substitution - return collectPatternSubstitutions(pattern->pattern->val.assignment-> - value, substitutions); + return collectPatternSubstitutions(pattern->pattern->val. + assignment->value, substitutions); } static TpmcPattern *collectConstructorSubstitutions(TpmcPattern *pattern, TpmcSubstitutionTable @@ -424,8 +424,8 @@ static TpmcPattern *collectConstructorSubstitutions(TpmcPattern *pattern, TpmcSu static TpmcPattern *collectComparisonSubstitutions(TpmcPattern *pattern, TpmcSubstitutionTable *substitutions) { pattern->pattern->val.comparison->previous = - collectPatternSubstitutions(pattern->pattern->val.comparison-> - previous, substitutions); + collectPatternSubstitutions(pattern->pattern->val. + comparison->previous, substitutions); pattern->pattern->val.comparison->current = collectPatternSubstitutions(pattern->pattern->val.comparison->current, substitutions); diff --git a/src/tpmc_match.c b/src/tpmc_match.c index c636404..f8878f3 100644 --- a/src/tpmc_match.c +++ b/src/tpmc_match.c @@ -268,8 +268,8 @@ static void populateSubPatternMatrixRowWithComponents(TpmcMatrix *matrix, } for (int i = 0; i < arity; i++) { setTpmcMatrixIndex(matrix, i, y, - pattern->pattern->val.constructor->components-> - entries[i]); + pattern->pattern->val.constructor-> + components->entries[i]); } LEAVE(populateSubPatternMatrixRowWithComponents); } @@ -511,8 +511,9 @@ static void collectPathsBoundByPattern(TpmcPattern *pattern, case TPMCPATTERNVALUE_TYPE_BIGINTEGER: break; case TPMCPATTERNVALUE_TYPE_CONSTRUCTOR: - collectPathsBoundByConstructor(pattern->pattern->val.constructor-> - components, boundVariables); + collectPathsBoundByConstructor(pattern->pattern->val. + constructor->components, + boundVariables); break; default: cant_happen("unrecognised type %d in collectPathsBoundByPattern", diff --git a/tools/makeAST.py b/tools/makeAST.py index 252d4a4..fd0075d 100644 --- a/tools/makeAST.py +++ b/tools/makeAST.py @@ -22,6 +22,7 @@ import sys import argparse import re +import os class Catalog: def __init__(self, typeName): @@ -1719,6 +1720,23 @@ def printGpl(file, document): print(f" * Generated from {file} by tools/makeAST.py") print(" */") +class Loader(yaml.SafeLoader): + + def __init__(self, stream): + + self._root = os.path.split(stream.name)[0] + + super(Loader, self).__init__(stream) + + def include(self, node): + + filename = os.path.join(self._root, self.construct_scalar(node)) + + with open(filename, 'r') as f: + return yaml.load(f, Loader) + +Loader.add_constructor('!include', Loader.include) + ################################################################## parser = argparse.ArgumentParser() @@ -1731,7 +1749,7 @@ def printGpl(file, document): stream = open(args.yaml, 'r') -document = yaml.load(stream, Loader=yaml.Loader) +document = yaml.load(stream, Loader) typeName = document['config']['name'] if 'includes' in document['config']: @@ -1765,6 +1783,10 @@ def printGpl(file, document): for name in document["primitives"]: catalog.add(Primitive(name, document["primitives"][name])) +if "external" in document: + for name in document["external"]: + catalog.add(Primitive(name, document["external"][name])) + if "arrays" in document: for name in document["arrays"]: catalog.add(SimpleArray(name, document["arrays"][name])) From d34fdb544bc26aa8b26e77f4ac29190602f86cb1 Mon Sep 17 00:00:00 2001 From: Bill Hails Date: Sat, 2 Mar 2024 13:48:07 +0000 Subject: [PATCH 06/33] renamed TcTypeDef to TcUserType --- src/print_compiler.c | 23 +++++---- src/tc.yaml | 10 ++-- src/tc_analyze.c | 117 ++++++++++++++++++++++--------------------- src/tc_helper.c | 12 ++--- src/tc_helper.h | 2 +- src/tpmc_logic.c | 8 +-- src/tpmc_match.c | 9 ++-- 7 files changed, 92 insertions(+), 89 deletions(-) diff --git a/src/print_compiler.c b/src/print_compiler.c index 70403f6..95587f1 100644 --- a/src/print_compiler.c +++ b/src/print_compiler.c @@ -41,7 +41,7 @@ static LamExp *compilePrinterForPair(TcPair *pair); static LamExp *compilePrinterForVar(TcVar *var, TcEnv *env); static LamExp *compilePrinterForInt(); static LamExp *compilePrinterForChar(); -static LamExp *compilePrinterForTypeDef(TcTypeDef *typeDef, TcEnv *env); +static LamExp *compilePrinterForUserType(TcUserType *userType, TcEnv *env); LamExp *compilePrinterForType(TcType *type, TcEnv *env) { LamExp *res = NULL; @@ -62,8 +62,8 @@ LamExp *compilePrinterForType(TcType *type, TcEnv *env) { case TCTYPE_TYPE_CHARACTER: res = compilePrinterForChar(); break; - case TCTYPE_TYPE_TYPEDEF: - res = compilePrinterForTypeDef(type->val.typeDef, env); + case TCTYPE_TYPE_USERTYPE: + res = compilePrinterForUserType(type->val.userType, env); break; default: cant_happen("unrecognised TcType %d in compilePrinterForType", @@ -96,10 +96,11 @@ static LamExp *compilePrinterForChar() { return makePrintChar(); } -static LamList *compilePrinterForTypeDefArgs(TcTypeDefArgs *args, TcEnv *env) { +static LamList *compilePrinterForUserTypeArgs(TcUserTypeArgs *args, + TcEnv *env) { if (args == NULL) return NULL; - LamList *next = compilePrinterForTypeDefArgs(args->next, env); + LamList *next = compilePrinterForUserTypeArgs(args->next, env); int save = PROTECT(next); LamExp *this = compilePrinterForType(args->type, env); PROTECT(this); @@ -113,20 +114,20 @@ static LamExp *compilePrinterForString() { return newLamExp(LAMEXP_TYPE_VAR, LAMEXP_VAL_VAR(name)); } -static LamExp *compilePrinterForTypeDef(TcTypeDef *typeDef, TcEnv *env) { - if (typeDef->name == listSymbol()) { - if (typeDef->args - && typeDef->args->type->type == TCTYPE_TYPE_CHARACTER) { +static LamExp *compilePrinterForUserType(TcUserType *userType, TcEnv *env) { + if (userType->name == listSymbol()) { + if (userType->args + && userType->args->type->type == TCTYPE_TYPE_CHARACTER) { return compilePrinterForString(); } } - HashSymbol *name = makePrintName("print$", typeDef->name->name); + HashSymbol *name = makePrintName("print$", userType->name->name); if (!getFromTcEnv(env, name, NULL)) { return makeSymbolExpr("print$"); } LamExp *exp = newLamExp(LAMEXP_TYPE_VAR, LAMEXP_VAL_VAR(name)); int save = PROTECT(exp); - LamList *args = compilePrinterForTypeDefArgs(typeDef->args, env); + LamList *args = compilePrinterForUserTypeArgs(userType->args, env); PROTECT(args); int nargs = countLamList(args); if (nargs == 0) { diff --git a/src/tc.yaml b/src/tc.yaml index 76a9191..8dd5fcf 100644 --- a/src/tc.yaml +++ b/src/tc.yaml @@ -44,13 +44,13 @@ structs: first: TcType second: TcType - TcTypeDef: + TcUserType: name: HashSymbol - args: TcTypeDefArgs + args: TcUserTypeArgs - TcTypeDefArgs: + TcUserTypeArgs: type: TcType - next: TcTypeDefArgs + next: TcUserTypeArgs TcVar: name: HashSymbol @@ -69,6 +69,6 @@ unions: smallinteger: void_ptr biginteger: void_ptr character: void_ptr - typeDef: TcTypeDef + userType: TcUserType primitives: !include primitives.yaml diff --git a/src/tc_analyze.c b/src/tc_analyze.c index bd32d4b..a533052 100644 --- a/src/tc_analyze.c +++ b/src/tc_analyze.c @@ -98,7 +98,7 @@ static TcType *analyzeBooleanExp(LamExp *exp, TcEnv *env, TcNg *ng); static TcType *analyzeCharacterExp(LamExp *exp, TcEnv *env, TcNg *ng); static TcType *freshRec(TcType *type, TcNg *ng, TcTypeTable *map); static TcType *lookup(TcEnv *env, HashSymbol *symbol, TcNg *ng); -static TcType *makeTypeDef(HashSymbol *name, TcTypeDefArgs *args); +static TcType *makeUserType(HashSymbol *name, TcUserTypeArgs *args); static int id_counter = 0; @@ -704,12 +704,12 @@ static TcType *analyzeLetRec(LamLetRec *letRec, TcEnv *env, TcNg *ng) { return res; } -static TcTypeDefArgs *makeTcTypeDefArgs(LamTypeArgs *lamTypeArgs, - TcTypeTable *map) { +static TcUserTypeArgs *makeTcUserTypeArgs(LamTypeArgs *lamTypeArgs, + TcTypeTable *map) { if (lamTypeArgs == NULL) { return NULL; } - TcTypeDefArgs *next = makeTcTypeDefArgs(lamTypeArgs->next, map); + TcUserTypeArgs *next = makeTcUserTypeArgs(lamTypeArgs->next, map); int save = PROTECT(next); TcType *name = NULL; if (!getTcTypeTable(map, lamTypeArgs->name, &name)) { @@ -718,26 +718,26 @@ static TcTypeDefArgs *makeTcTypeDefArgs(LamTypeArgs *lamTypeArgs, setTcTypeTable(map, lamTypeArgs->name, name); UNPROTECT(save2); } - TcTypeDefArgs *this = newTcTypeDefArgs(name, next); + TcUserTypeArgs *this = newTcUserTypeArgs(name, next); UNPROTECT(save); return this; } -static TcType *makeTypeDef(HashSymbol *name, TcTypeDefArgs *args) { - TcTypeDef *tcTypeDef = newTcTypeDef(name, args); - int save = PROTECT(tcTypeDef); +static TcType *makeUserType(HashSymbol *name, TcUserTypeArgs *args) { + TcUserType *tcUserType = newTcUserType(name, args); + int save = PROTECT(tcUserType); TcType *res = - newTcType(TCTYPE_TYPE_TYPEDEF, TCTYPE_VAL_TYPEDEF(tcTypeDef)); + newTcType(TCTYPE_TYPE_USERTYPE, TCTYPE_VAL_USERTYPE(tcUserType)); UNPROTECT(save); - DEBUG("makeTypeDef: %s %p", name->name, res); - IFDEBUG(ppTcTypeDef(tcTypeDef)); + DEBUG("makeUserType: %s %p", name->name, res); + IFDEBUG(ppTcUserType(tcUserType)); return res; } -static TcType *makeTcTypeDefType(LamType *lamType, TcTypeTable *map) { - TcTypeDefArgs *args = makeTcTypeDefArgs(lamType->args, map); +static TcType *makeTcUserType(LamType *lamType, TcTypeTable *map) { + TcUserTypeArgs *args = makeTcUserTypeArgs(lamType->args, map); int save = PROTECT(args); - TcType *res = makeTypeDef(lamType->name, args); + TcType *res = makeUserType(lamType->name, args); UNPROTECT(save); return res; } @@ -745,16 +745,16 @@ static TcType *makeTcTypeDefType(LamType *lamType, TcTypeTable *map) { static TcType *makeTypeConstructorArg(LamTypeConstructorType *arg, TcTypeTable *map); -static TcTypeDefArgs *makeTypeDefArgs(LamTypeConstructorArgs *args, - TcTypeTable *map) { +static TcUserTypeArgs *makeUserTypeArgs(LamTypeConstructorArgs *args, + TcTypeTable *map) { if (args == NULL) { return NULL; } - TcTypeDefArgs *next = makeTypeDefArgs(args->next, map); + TcUserTypeArgs *next = makeUserTypeArgs(args->next, map); int save = PROTECT(next); TcType *arg = makeTypeConstructorArg(args->arg, map); PROTECT(arg); - TcTypeDefArgs *this = newTcTypeDefArgs(arg, next); + TcUserTypeArgs *this = newTcUserTypeArgs(arg, next); UNPROTECT(save); return this; } @@ -763,9 +763,9 @@ static TcType *makeTypeConstructorApplication(LamTypeFunction *func, TcTypeTable *map) { // this code is building the inner application of a type, i.e. // list(t) in the context of t -> list(t) -> list(t) - TcTypeDefArgs *args = makeTypeDefArgs(func->args, map); + TcUserTypeArgs *args = makeUserTypeArgs(func->args, map); int save = PROTECT(args); - TcType *res = makeTypeDef(func->name, args); + TcType *res = makeUserType(func->name, args); UNPROTECT(save); return res; } @@ -828,7 +828,7 @@ static void collectTypeDef(LamTypeDef *lamTypeDef, TcEnv *env) { TcTypeTable *map = newTcTypeTable(); int save = PROTECT(map); LamType *lamType = lamTypeDef->type; - TcType *tcType = makeTcTypeDefType(lamType, map); + TcType *tcType = makeTcUserType(lamType, map); PROTECT(tcType); for (LamTypeConstructorList *list = lamTypeDef->constructors; list != NULL; list = list->next) { @@ -1191,27 +1191,27 @@ static TcType *freshPair(TcPair *pair, TcNg *ng, TcTypeTable *map) { return res; } -static TcTypeDefArgs *freshTypeDefArgs(TcTypeDefArgs *args, TcNg *ng, - TcTypeTable *map) { +static TcUserTypeArgs *freshUserTypeArgs(TcUserTypeArgs *args, TcNg *ng, + TcTypeTable *map) { if (args == NULL) return NULL; - TcTypeDefArgs *next = freshTypeDefArgs(args->next, ng, map); + TcUserTypeArgs *next = freshUserTypeArgs(args->next, ng, map); int save = PROTECT(next); TcType *type = freshRec(args->type, ng, map); PROTECT(type); - TcTypeDefArgs *this = newTcTypeDefArgs(type, next); + TcUserTypeArgs *this = newTcUserTypeArgs(type, next); UNPROTECT(save); return this; } -static TcType *freshTypeDef(TcTypeDef *typeDef, TcNg *ng, TcTypeTable *map) { - ENTER(freshTypeDef); - TcTypeDefArgs *args = freshTypeDefArgs(typeDef->args, ng, map); +static TcType *freshUserType(TcUserType *userType, TcNg *ng, TcTypeTable *map) { + ENTER(freshUserType); + TcUserTypeArgs *args = freshUserTypeArgs(userType->args, ng, map); int save = PROTECT(args); - TcType *res = makeTypeDef(typeDef->name, args); + TcType *res = makeUserType(userType->name, args); UNPROTECT(save); - LEAVE(freshTypeDef); - IFDEBUG(ppTcTypeDef(typeDef)); + LEAVE(freshUserType); + IFDEBUG(ppTcUserType(userType)); IFDEBUG(ppTcType(res)); return res; } @@ -1272,8 +1272,8 @@ static TcType *freshRec(TcType *type, TcNg *ng, TcTypeTable *map) { case TCTYPE_TYPE_BIGINTEGER: case TCTYPE_TYPE_CHARACTER: return type; - case TCTYPE_TYPE_TYPEDEF:{ - TcType *res = freshTypeDef(type->val.typeDef, ng, map); + case TCTYPE_TYPE_USERTYPE:{ + TcType *res = freshUserType(type->val.userType, ng, map); return res; } default: @@ -1315,12 +1315,12 @@ static void addToNg(TcNg *ng, HashSymbol *symbol, TcType *type) { } static TcType *makeBoolean() { - TcType *res = makeTypeDef(boolSymbol(), NULL); + TcType *res = makeUserType(boolSymbol(), NULL); return res; } static TcType *makeStarship() { - TcType *res = makeTypeDef(starshipSymbol(), NULL); + TcType *res = makeUserType(starshipSymbol(), NULL); return res; } @@ -1504,17 +1504,17 @@ static bool unifyPairs(TcPair *a, TcPair *b) { return res; } -static bool unifyTypeDefs(TcTypeDef *a, TcTypeDef *b) { +static bool unifyUserTypes(TcUserType *a, TcUserType *b) { if (a->name != b->name) { can_happen("unification failed[1]"); - ppTcTypeDef(a); + ppTcUserType(a); eprintf(" vs "); - ppTcTypeDef(b); + ppTcUserType(b); eprintf("\n"); return false; } - TcTypeDefArgs *aArgs = a->args; - TcTypeDefArgs *bArgs = b->args; + TcUserTypeArgs *aArgs = a->args; + TcUserTypeArgs *bArgs = b->args; while (aArgs != NULL && bArgs != NULL) { if (!unify(aArgs->type, bArgs->type)) { return false; @@ -1524,9 +1524,9 @@ static bool unifyTypeDefs(TcTypeDef *a, TcTypeDef *b) { } if (aArgs != NULL || bArgs != NULL) { can_happen("unification failed[2]"); - ppTcTypeDef(a); + ppTcUserType(a); eprintf(" vs "); - ppTcTypeDef(b); + ppTcUserType(b); eprintf("\n"); return false; } @@ -1537,7 +1537,9 @@ static bool unify(TcType *a, TcType *b) { a = prune(a); b = prune(b); DEBUG("UNIFY"); - IFDEBUG(ppTcType(a); eprintf(" WITH "); ppTcType(b)); + IFDEBUG(ppTcType(a); + eprintf(" WITH "); + ppTcType(b)); if (a == b) return true; if (a->type == TCTYPE_TYPE_VAR) { @@ -1579,8 +1581,8 @@ static bool unify(TcType *a, TcType *b) { case TCTYPE_TYPE_BIGINTEGER: case TCTYPE_TYPE_CHARACTER: return true; - case TCTYPE_TYPE_TYPEDEF: - return unifyTypeDefs(a->val.typeDef, b->val.typeDef); + case TCTYPE_TYPE_USERTYPE: + return unifyUserTypes(a->val.userType, b->val.userType); default: cant_happen("unrecognised type %d in unify", a->type); } @@ -1588,7 +1590,7 @@ static bool unify(TcType *a, TcType *b) { cant_happen("reached end of unify"); } -static void pruneTypeDefArgs(TcTypeDefArgs *args) { +static void pruneUserTypeArgs(TcUserTypeArgs *args) { while (args != NULL) { args->type = prune(args->type); args = args->next; @@ -1603,8 +1605,8 @@ static TcType *prune(TcType *t) { t->val.var->instance = prune(t->val.var->instance); return t->val.var->instance; } - } else if (t->type == TCTYPE_TYPE_TYPEDEF) { - pruneTypeDefArgs(t->val.typeDef->args); + } else if (t->type == TCTYPE_TYPE_USERTYPE) { + pruneUserTypeArgs(t->val.userType->args); } else if (t->type == TCTYPE_TYPE_FUNCTION) { t->val.function->arg = prune(t->val.function->arg); t->val.function->result = prune(t->val.function->result); @@ -1620,12 +1622,12 @@ static bool samePairType(TcPair *a, TcPair *b) { return sameType(a->first, b->first) && sameType(a->second, b->second); } -static bool sameTypeDefType(TcTypeDef *a, TcTypeDef *b) { +static bool sameUserType(TcUserType *a, TcUserType *b) { if (a->name != b->name) { return false; } - TcTypeDefArgs *aArgs = a->args; - TcTypeDefArgs *bArgs = b->args; + TcUserTypeArgs *aArgs = a->args; + TcUserTypeArgs *bArgs = b->args; while (aArgs != NULL && bArgs != NULL) { if (!sameType(aArgs->type, bArgs->type)) return false; @@ -1658,8 +1660,8 @@ static bool sameType(TcType *a, TcType *b) { case TCTYPE_TYPE_SMALLINTEGER: case TCTYPE_TYPE_CHARACTER: return true; - case TCTYPE_TYPE_TYPEDEF: - return sameTypeDefType(a->val.typeDef, b->val.typeDef); + case TCTYPE_TYPE_USERTYPE: + return sameUserType(a->val.userType, b->val.userType); default: cant_happen("unrecognised type %d in sameType", a->type); } @@ -1683,8 +1685,9 @@ static bool occursInPair(TcType *var, TcPair *pair) { return occursInType(var, pair->first) || occursInType(var, pair->second); } -static bool occursInTypeDef(TcType *var, TcTypeDef *typeDef) { - for (TcTypeDefArgs *args = typeDef->args; args != NULL; args = args->next) { +static bool occursInUserType(TcType *var, TcUserType *userType) { + for (TcUserTypeArgs *args = userType->args; args != NULL; + args = args->next) { if (occursInType(var, args->type)) return true; } @@ -1703,8 +1706,8 @@ static bool occursIn(TcType *a, TcType *b) { case TCTYPE_TYPE_BIGINTEGER: case TCTYPE_TYPE_CHARACTER: return false; - case TCTYPE_TYPE_TYPEDEF: - return occursInTypeDef(a, b->val.typeDef); + case TCTYPE_TYPE_USERTYPE: + return occursInUserType(a, b->val.userType); default: cant_happen("unrecognised type %d in occursIn", b->type); } diff --git a/src/tc_helper.c b/src/tc_helper.c index 1e296a4..def80bd 100644 --- a/src/tc_helper.c +++ b/src/tc_helper.c @@ -43,8 +43,8 @@ void ppTcType(TcType *type) { case TCTYPE_TYPE_CHARACTER: eprintf("char"); break; - case TCTYPE_TYPE_TYPEDEF: - ppTcTypeDef(type->val.typeDef); + case TCTYPE_TYPE_USERTYPE: + ppTcUserType(type->val.userType); break; default: cant_happen("unrecognized type %d in ppTcType", type->type); @@ -75,7 +75,7 @@ void ppTcVar(TcVar *var) { } } -static void ppTypeDefArgs(TcTypeDefArgs *args) { +static void ppUserTypeArgs(TcUserTypeArgs *args) { while (args != NULL) { ppTcType(args->type); if (args->next) @@ -84,9 +84,9 @@ static void ppTypeDefArgs(TcTypeDefArgs *args) { } } -void ppTcTypeDef(TcTypeDef *typeDef) { - eprintf("%s(", typeDef->name->name); - ppTypeDefArgs(typeDef->args); +void ppTcUserType(TcUserType *userType) { + eprintf("%s(", userType->name->name); + ppUserTypeArgs(userType->args); eprintf(")"); } diff --git a/src/tc_helper.h b/src/tc_helper.h index ad5b990..5fe5d32 100644 --- a/src/tc_helper.h +++ b/src/tc_helper.h @@ -25,7 +25,7 @@ void ppTcType(TcType *type); void ppTcFunction(TcFunction *function); void ppTcPair(TcPair *pair); void ppTcVar(TcVar *var); -void ppTcTypeDef(TcTypeDef *typeDef); +void ppTcUserType(TcUserType *userType); bool getFromTcEnv(TcEnv *env, HashSymbol *symbol, TcType **type); #endif diff --git a/src/tpmc_logic.c b/src/tpmc_logic.c index d263a26..9c0b819 100644 --- a/src/tpmc_logic.c +++ b/src/tpmc_logic.c @@ -405,8 +405,8 @@ static TpmcPattern *collectAssignmentSubstitutions(TpmcPattern *pattern, TpmcSub pattern->pattern->val.assignment->name, pattern->path); // we no longer need to remember this is an assignment now we have the substitution - return collectPatternSubstitutions(pattern->pattern->val. - assignment->value, substitutions); + return collectPatternSubstitutions(pattern->pattern->val.assignment-> + value, substitutions); } static TpmcPattern *collectConstructorSubstitutions(TpmcPattern *pattern, TpmcSubstitutionTable @@ -424,8 +424,8 @@ static TpmcPattern *collectConstructorSubstitutions(TpmcPattern *pattern, TpmcSu static TpmcPattern *collectComparisonSubstitutions(TpmcPattern *pattern, TpmcSubstitutionTable *substitutions) { pattern->pattern->val.comparison->previous = - collectPatternSubstitutions(pattern->pattern->val. - comparison->previous, substitutions); + collectPatternSubstitutions(pattern->pattern->val.comparison-> + previous, substitutions); pattern->pattern->val.comparison->current = collectPatternSubstitutions(pattern->pattern->val.comparison->current, substitutions); diff --git a/src/tpmc_match.c b/src/tpmc_match.c index f8878f3..c636404 100644 --- a/src/tpmc_match.c +++ b/src/tpmc_match.c @@ -268,8 +268,8 @@ static void populateSubPatternMatrixRowWithComponents(TpmcMatrix *matrix, } for (int i = 0; i < arity; i++) { setTpmcMatrixIndex(matrix, i, y, - pattern->pattern->val.constructor-> - components->entries[i]); + pattern->pattern->val.constructor->components-> + entries[i]); } LEAVE(populateSubPatternMatrixRowWithComponents); } @@ -511,9 +511,8 @@ static void collectPathsBoundByPattern(TpmcPattern *pattern, case TPMCPATTERNVALUE_TYPE_BIGINTEGER: break; case TPMCPATTERNVALUE_TYPE_CONSTRUCTOR: - collectPathsBoundByConstructor(pattern->pattern->val. - constructor->components, - boundVariables); + collectPathsBoundByConstructor(pattern->pattern->val.constructor-> + components, boundVariables); break; default: cant_happen("unrecognised type %d in collectPathsBoundByPattern", From fbde13acfa9a3c976051461c4e06b9ddba43ebf9 Mon Sep 17 00:00:00 2001 From: Bill Hails Date: Sat, 2 Mar 2024 13:55:08 +0000 Subject: [PATCH 07/33] formatting --- fn/redBlack.fn | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/fn/redBlack.fn b/fn/redBlack.fn index 602d5a7..fe2f0b8 100644 --- a/fn/redBlack.fn +++ b/fn/redBlack.fn @@ -21,7 +21,9 @@ let (red(red(a, x, b), y, c), z, d) | (red(a, x, red(b, y, c)), z, d) | (a, x, red(red(b, y, c), z, d)) | - (a, x, red(b, y, red(c, z, d))) { red(black(a, x, b), y, black(c, z, d)) } + (a, x, red(b, y, red(c, z, d))) { + red(black(a, x, b), y, black(c, z, d)) + } (a, x, b) { black(a, x, b) } } @@ -63,7 +65,8 @@ let fn part_flatten { (red(left, t, right), already_flat) | (black(left, t, right), already_flat) { - part_flatten(left, t @ part_flatten(right, already_flat)) + part_flatten(left, + t @ part_flatten(right, already_flat)) } (leaf, already_flat) { already_flat } } @@ -74,15 +77,19 @@ in makeList( print( makeSet( - "kgimtseettepmupybbbmplgntqzutrfxqarkivirlbjqjigntslfewhnjouuyiepnswymk" - "fpyovclntwbmhngufnoeidjfmhxxaqmqiaoodslwlwwnzxtdxawnfxbiesjtdwmrzkbdoz" - "zyppmdyzhvyhfadldkflwiwvmfutfeckzsqulxlenvpwpbqdjwxpphhtyeuojmvmhgwcis" - "xevzlvbtnobaaokqbutzqumbzlgqwqsludnrygnynsqcvjekjouyyplgyzlhlsbakaknja" - "uctsspolsvifpwrklfxjfbxrnkecgmypfkbxonkusuzigleakcrnqhktvjonlfiuoeoupu" - "wdtzyytsmggyspdoswafjvceqyzgtksocdhszgybbrrivirlcgozvxgtvtxgyuukntggim" - "fsoprufwmdngqkabxolitehdjbiqhdjexiaojatkhdjdcpckbxdxwfocqjchijeylcyhox" - "nywikniqzpqeeqtucengrvgbbntwmvyeoddjxlgqablttpyrmxlckrvstwmvmfcvmbskci" - "vvsjlchmoczdnbczvznnkiaabonyiqvjmbiyeddetcczprvjfmhmshxmknhonxyxgbgpaw" - "kahqbknbqpargbnnunwgxphhlvedlyazkfzavezdtlfefpvjiooocpwspyalpahadximva" - "auocirfgpijbhqskcuuynvcvtndifklhczerlvjpfpjhnkxxprrsktdfnrrmoypigecxbk" - "zxflgtmdxxzfvdvesewzqotfdlqfibzkchndafnmxirrruol"))) + "kgimtseettepmupybbbmplgntqzutrfxqarkivirlbjqjigntslfewhn" + "jouuyiepnswymkfpyovclntwbmhngufnoeidjfmhxxaqmqiaoodslwlw" + "wnzxtdxawnfxbiesjtdwmrzkbdozzyppmdyzhvyhfadldkflwiwvmfut" + "feckzsqulxlenvpwpbqdjwxpphhtyeuojmvmhgwcisxevzlvbtnobaao" + "kqbutzqumbzlgqwqsludnrygnynsqcvjekjouyyplgyzlhlsbakaknja" + "uctsspolsvifpwrklfxjfbxrnkecgmypfkbxonkusuzigleakcrnqhkt" + "vjonlfiuoeoupuwdtzyytsmggyspdoswafjvceqyzgtksocdhszgybbr" + "rivirlcgozvxgtvtxgyuukntggimfsoprufwmdngqkabxolitehdjbiq" + "hdjexiaojatkhdjdcpckbxdxwfocqjchijeylcyhoxnywikniqzpqeeq" + "tucengrvgbbntwmvyeoddjxlgqablttpyrmxlckrvstwmvmfcvmbskci" + "vvsjlchmoczdnbczvznnkiaabonyiqvjmbiyeddetcczprvjfmhmshxm" + "knhonxyxgbgpawkahqbknbqpargbnnunwgxphhlvedlyazkfzavezdtl" + "fefpvjiooocpwspyalpahadximvaauocirfgpijbhqskcuuynvcvtndi" + "fklhczerlvjpfpjhnkxxprrsktdfnrrmoypigecxbkzxflgtmdxxzfvd" + "vesewzqotfdlqfibzkchndafnmxirrruol"))); + puts("\n") From c54b2f5dc9a5ddc949d90f1c3f5a2a231b2870c2 Mon Sep 17 00:00:00 2001 From: Bill Hails Date: Sat, 2 Mar 2024 14:19:55 +0000 Subject: [PATCH 08/33] gpl in primitives.yaml --- src/primitives.yaml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/primitives.yaml b/src/primitives.yaml index b81b57d..8581dc2 100644 --- a/src/primitives.yaml +++ b/src/primitives.yaml @@ -1,3 +1,21 @@ +# +# CEKF - VM supporting amb +# Copyright (C) 2022-2023 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 . +# + # common primitive types not defined by the schemas HashSymbol: From 660280b5b429d2fa5cefdb859f0de83cb5bb3f32 Mon Sep 17 00:00:00 2001 From: Bill Hails Date: Sat, 2 Mar 2024 17:18:14 +0000 Subject: [PATCH 09/33] minor formatting changes --- .indent.pro | 23 +++++++++++++++++++++++ Makefile | 4 ++-- README.md | 29 +++++++++++++++++++---------- src/lambda_conversion.c | 17 +++++++++++------ src/lambda_substitution.c | 5 +---- src/tc_analyze.c | 4 +--- src/tpmc_logic.c | 8 ++++---- src/tpmc_match.c | 9 +++++---- 8 files changed, 66 insertions(+), 33 deletions(-) create mode 100644 .indent.pro diff --git a/.indent.pro b/.indent.pro new file mode 100644 index 0000000..49e7d3c --- /dev/null +++ b/.indent.pro @@ -0,0 +1,23 @@ +--blank-lines-after-procedures +--braces-on-func-def-line +--braces-on-if-line +--braces-on-struct-decl-line +--case-brace-indentation4 +--case-indentation4 +--cuddle-do-while +--cuddle-else +--dont-break-function-decl-args +--dont-break-procedure-type +--ignore-newlines +--indent-level4 +--no-space-after-function-call-names +--no-tabs +--pointer-align-right +--preserve-mtime +--preprocessor-indentation4 +--space-after-for +--space-after-if +--space-after-while +--spaces-around-initializers +--struct-brace-indentation1 +--swallow-optional-blank-lines diff --git a/Makefile b/Makefile index d1ac36c..8e1d1c7 100644 --- a/Makefile +++ b/Makefile @@ -137,8 +137,8 @@ profile: all rm -f callgrind.out.* valgrind --tool=callgrind ./$(TARGET) -indent: .typedefs - (cd src; indent `cat ../.typedefs | sort -u | xargs` -T bigint_word -T BigInt -T IntegerBinOp -T Control -T Stack -T Env -T Snapshot -T Kont -T ValueList -T Clo -T Fail -T Vec -T ProtectionStack -T HashSymbol -T hash_t -T Header -T PmModule -T HashTable -T byte -T word -T ByteCodes -T ByteCodeArray -T Value -T FILE *.[ch]) +indent: .typedefs .indent.pro + indent `cat .typedefs | sort -u | xargs` -T bigint_word -T BigInt -T IntegerBinOp -T Control -T Stack -T Env -T Snapshot -T Kont -T ValueList -T Clo -T Fail -T Vec -T ProtectionStack -T HashSymbol -T hash_t -T Header -T PmModule -T HashTable -T byte -T word -T ByteCodes -T ByteCodeArray -T Value -T FILE src/*.[ch] .typedefs: .generated diff --git a/README.md b/README.md index 677c523..5bf36de 100644 --- a/README.md +++ b/README.md @@ -67,16 +67,25 @@ the $step$ function: one to deal with `amb` and one to deal with `back`. ```mermaid flowchart TD - -source --> -AST[Parser] --abstract syntax--> -lambda[Lambda Conversion] --lambda calculus--> -check[Type Checking] --typed lambda calculus--> -anf[A-Normal Form Conversion] --ANF--> -desugaring[Desugaring] --ANF--> -static[Static Analysis] --annotated ANF--> -Bytecode[Bytecode Generation] --bytecode--> -VM +classDef process fill:#aef; +source(Source) --> +parser([Parser]):::process --> +ast(AST) --> +lc([Lambda Conversion]):::process <--> tpmc([Tpmc]):::process +lc <--> pg([Print Function Generator]):::process +lc <--> ci([Constructor Inlining]):::process +tpmc <--> vs([Variable Substitution]):::process +lc ----> lambda1(Plain Lambda Form) +lambda1 --> tc([Type Checking]):::process +tc <--> pc([Print Compiler]):::process +tc ---> lambda2(Plain Lambda Form) +lambda2 --> anfc([A-Normal Form Conversion]):::process +anfc --> anf(ANF) +anf --> desug([Desugaring]):::process +desug --> danf(Desugared ANF) +danf --> bcc([Bytecode Compiler]):::process +bcc --> bc(Byte Code) +bc --> cekf([CEKF Runtime VM]):::process ``` All stages basically complete, but it needs a lot of testing now. diff --git a/src/lambda_conversion.c b/src/lambda_conversion.c index 97f9300..434c3aa 100644 --- a/src/lambda_conversion.c +++ b/src/lambda_conversion.c @@ -75,13 +75,18 @@ static int count ## type (type *list) { \ return count; \ } -MAKE_COUNT_LIST(LamLetRecBindings) MAKE_COUNT_LIST(AstTypeList) -MAKE_COUNT_LIST(AstExpressions) MAKE_COUNT_LIST(AstArgList) +/* *INDENT-OFF* */ +MAKE_COUNT_LIST(LamLetRecBindings) +MAKE_COUNT_LIST(AstTypeList) +MAKE_COUNT_LIST(AstExpressions) +MAKE_COUNT_LIST(AstArgList) MAKE_COUNT_LIST(AstCompositeFunction) - static bool inPreamble = true; // preamble is treated specially - static bool preambleLocked = false; +/* *INDENT-ON* */ - LamExp *lamConvertNest(AstNest *nest, LamContext *env) { +static bool inPreamble = true; // preamble is treated specially +static bool preambleLocked = false; + +LamExp *lamConvertNest(AstNest *nest, LamContext *env) { ENTER(lamConvertNest); bool hasLock = inPreamble && !preambleLocked; if (hasLock) @@ -123,7 +128,7 @@ MAKE_COUNT_LIST(AstCompositeFunction) UNPROTECT(save); LEAVE(lamConvertNest); return result; - } +} static LamExp *lamConvertIff(AstIff *iff, LamContext *context) { ENTER(lamConvertIff); diff --git a/src/lambda_substitution.c b/src/lambda_substitution.c index 29429b8..ae8e2fb 100644 --- a/src/lambda_substitution.c +++ b/src/lambda_substitution.c @@ -16,10 +16,7 @@ * along with this program. If not, see . */ -// conversion of the AST generated by the parser -// to an intermediate "plain" lambda calculus which -// will then be fed into the type checker and the -// A-Normal Form converter. +// Substitution of variables in the bodies of functions, called by the TPMC. #include #include diff --git a/src/tc_analyze.c b/src/tc_analyze.c index a533052..0f52310 100644 --- a/src/tc_analyze.c +++ b/src/tc_analyze.c @@ -1537,9 +1537,7 @@ static bool unify(TcType *a, TcType *b) { a = prune(a); b = prune(b); DEBUG("UNIFY"); - IFDEBUG(ppTcType(a); - eprintf(" WITH "); - ppTcType(b)); + IFDEBUG(ppTcType(a); eprintf(" WITH "); ppTcType(b)); if (a == b) return true; if (a->type == TCTYPE_TYPE_VAR) { diff --git a/src/tpmc_logic.c b/src/tpmc_logic.c index 9c0b819..d263a26 100644 --- a/src/tpmc_logic.c +++ b/src/tpmc_logic.c @@ -405,8 +405,8 @@ static TpmcPattern *collectAssignmentSubstitutions(TpmcPattern *pattern, TpmcSub pattern->pattern->val.assignment->name, pattern->path); // we no longer need to remember this is an assignment now we have the substitution - return collectPatternSubstitutions(pattern->pattern->val.assignment-> - value, substitutions); + return collectPatternSubstitutions(pattern->pattern->val. + assignment->value, substitutions); } static TpmcPattern *collectConstructorSubstitutions(TpmcPattern *pattern, TpmcSubstitutionTable @@ -424,8 +424,8 @@ static TpmcPattern *collectConstructorSubstitutions(TpmcPattern *pattern, TpmcSu static TpmcPattern *collectComparisonSubstitutions(TpmcPattern *pattern, TpmcSubstitutionTable *substitutions) { pattern->pattern->val.comparison->previous = - collectPatternSubstitutions(pattern->pattern->val.comparison-> - previous, substitutions); + collectPatternSubstitutions(pattern->pattern->val. + comparison->previous, substitutions); pattern->pattern->val.comparison->current = collectPatternSubstitutions(pattern->pattern->val.comparison->current, substitutions); diff --git a/src/tpmc_match.c b/src/tpmc_match.c index c636404..f8878f3 100644 --- a/src/tpmc_match.c +++ b/src/tpmc_match.c @@ -268,8 +268,8 @@ static void populateSubPatternMatrixRowWithComponents(TpmcMatrix *matrix, } for (int i = 0; i < arity; i++) { setTpmcMatrixIndex(matrix, i, y, - pattern->pattern->val.constructor->components-> - entries[i]); + pattern->pattern->val.constructor-> + components->entries[i]); } LEAVE(populateSubPatternMatrixRowWithComponents); } @@ -511,8 +511,9 @@ static void collectPathsBoundByPattern(TpmcPattern *pattern, case TPMCPATTERNVALUE_TYPE_BIGINTEGER: break; case TPMCPATTERNVALUE_TYPE_CONSTRUCTOR: - collectPathsBoundByConstructor(pattern->pattern->val.constructor-> - components, boundVariables); + collectPathsBoundByConstructor(pattern->pattern->val. + constructor->components, + boundVariables); break; default: cant_happen("unrecognised type %d in collectPathsBoundByPattern", From 7c7d4ef74a8347fe13844c7ad49c4161d4dc9074 Mon Sep 17 00:00:00 2001 From: Bill Hails Date: Sun, 3 Mar 2024 12:43:15 +0000 Subject: [PATCH 10/33] simplify lambda conversion, fix indent --- src/lambda_conversion.c | 99 ++++++++++++++++++++++------------------- src/tc_analyze.c | 2 + src/tpmc_logic.c | 8 ++-- src/tpmc_match.c | 15 ++++--- 4 files changed, 67 insertions(+), 57 deletions(-) diff --git a/src/lambda_conversion.c b/src/lambda_conversion.c index 434c3aa..26739ee 100644 --- a/src/lambda_conversion.c +++ b/src/lambda_conversion.c @@ -586,48 +586,65 @@ static LamExp *makePrimApp(HashSymbol *symbol, LamList *args) { return NULL; } -static LamExp *convertFunCall(AstFunCall *funCall, LamContext *env) { - AstExpression *function = funCall->function; - LamList *args = convertExpressions(funCall->arguments, env); - int actualNargs = countAstExpressions(funCall->arguments); - int save = PROTECT(args); - // see if it's a type constructor we can inline FIXME - or a primitive - if (function->type == AST_EXPRESSION_TYPE_SYMBOL) { - HashSymbol *symbol = function->val.symbol; - LamExp *primApp = makePrimApp(symbol, args); - if (primApp != NULL) { - return primApp; +static LamExp *inlineConstructor(HashSymbol *symbol, LamList *args, + LamContext *env) { + LamTypeConstructorInfo *info = lookupInLamContext(env, symbol); + if (info != NULL) { + int actualNargs = countLamList(args); + if (info->needsVec) { + if (actualNargs == info->arity) { + return makeConstruct(symbol, info->index, args); + } else { + cant_happen("wrong number of arguments to constructor %s", + symbol->name); + } } else { - LamTypeConstructorInfo *info = lookupInLamContext(env, symbol); - if (info != NULL) { - if (info->needsVec) { - if (actualNargs == info->arity) { - LamExp *inLine = - makeConstruct(symbol, info->index, args); - UNPROTECT(save); - return inLine; - } else { - cant_happen - ("wrong number of arguments to constructor %s", - symbol->name); - } - } else { - cant_happen("arguments to empty constructor %s", - symbol->name); - } + if (actualNargs > 0) { + cant_happen("arguments to constant constructor %s", + symbol->name); } + return makeConstant(symbol, info->index); } } - // otherwise we convert as normal - LamExp *fun = convertExpression(function, env); - (void) PROTECT(fun); + return NULL; +} + +static LamExp *convertApplication(AstFunCall *funCall, LamList *args, + LamContext *env) { + int actualNargs = countAstExpressions(funCall->arguments); + LamExp *fun = convertExpression(funCall->function, env); + int save = PROTECT(fun); LamApply *apply = newLamApply(fun, actualNargs, args); - (void) PROTECT(apply); + PROTECT(apply); LamExp *result = newLamExp(LAMEXP_TYPE_APPLY, LAMEXP_VAL_APPLY(apply)); UNPROTECT(save); return result; } +static LamExp *convertFunCall(AstFunCall *funCall, LamContext *env) { + LamList *args = convertExpressions(funCall->arguments, env); + int save = PROTECT(args); + LamExp *result = NULL; + if (funCall->function->type == AST_EXPRESSION_TYPE_SYMBOL) { + HashSymbol *symbol = funCall->function->val.symbol; + result = makePrimApp(symbol, args); + if (result != NULL) { + UNPROTECT(save); + return result; + } + // see if it's a type constructor we can inline FIXME - or a primitive + result = inlineConstructor(symbol, args, env); + if (result != NULL) { + UNPROTECT(save); + return result; + } + } + // otherwise we convert as normal + result = convertApplication(funCall, args, env); + UNPROTECT(save); + return result; +} + static LamLam *convertCompositeBodies(int nargs, AstCompositeFunction *fun, LamContext *env) { ENTER(convertCompositeBodies); @@ -671,22 +688,12 @@ static LamExp *convertCompositeFun(AstCompositeFunction *fun, LamContext *env) { } static LamExp *convertSymbol(HashSymbol *symbol, LamContext *env) { - LamTypeConstructorInfo *info = lookupInLamContext(env, symbol); - if (info == NULL) { - DEBUG("convertSymbol %s is not a constructor", symbol->name); + LamExp *result = inlineConstructor(symbol, NULL, env); + if (result == NULL) { symbol = dollarSubstitute(symbol); - LamExp *res = newLamExp(LAMEXP_TYPE_VAR, LAMEXP_VAL_VAR(symbol)); - return res; - } - DEBUG("convertSymbol %s is a constructor", symbol->name); - if (info->needsVec) { - if (info->arity > 0) { - cant_happen("too few arguments to constructor %s", symbol->name); - } - return makeConstruct(symbol, info->index, NULL); - } else { - return makeConstant(symbol, info->index); + result = newLamExp(LAMEXP_TYPE_VAR, LAMEXP_VAL_VAR(symbol)); } + return result; } static LamExp *convertExpression(AstExpression *expression, LamContext *env) { diff --git a/src/tc_analyze.c b/src/tc_analyze.c index 0f52310..7cb2c4d 100644 --- a/src/tc_analyze.c +++ b/src/tc_analyze.c @@ -1537,7 +1537,9 @@ static bool unify(TcType *a, TcType *b) { a = prune(a); b = prune(b); DEBUG("UNIFY"); + // *INDENT-OFF* IFDEBUG(ppTcType(a); eprintf(" WITH "); ppTcType(b)); + // *INDENT-ON* if (a == b) return true; if (a->type == TCTYPE_TYPE_VAR) { diff --git a/src/tpmc_logic.c b/src/tpmc_logic.c index d263a26..7d801da 100644 --- a/src/tpmc_logic.c +++ b/src/tpmc_logic.c @@ -405,8 +405,8 @@ static TpmcPattern *collectAssignmentSubstitutions(TpmcPattern *pattern, TpmcSub pattern->pattern->val.assignment->name, pattern->path); // we no longer need to remember this is an assignment now we have the substitution - return collectPatternSubstitutions(pattern->pattern->val. - assignment->value, substitutions); + TpmcPattern *value = pattern->pattern->val.assignment->value; + return collectPatternSubstitutions(value, substitutions); } static TpmcPattern *collectConstructorSubstitutions(TpmcPattern *pattern, TpmcSubstitutionTable @@ -423,9 +423,9 @@ static TpmcPattern *collectConstructorSubstitutions(TpmcPattern *pattern, TpmcSu static TpmcPattern *collectComparisonSubstitutions(TpmcPattern *pattern, TpmcSubstitutionTable *substitutions) { + TpmcPattern *previous = pattern->pattern->val.comparison->previous; pattern->pattern->val.comparison->previous = - collectPatternSubstitutions(pattern->pattern->val. - comparison->previous, substitutions); + collectPatternSubstitutions(previous, substitutions); pattern->pattern->val.comparison->current = collectPatternSubstitutions(pattern->pattern->val.comparison->current, substitutions); diff --git a/src/tpmc_match.c b/src/tpmc_match.c index f8878f3..aee9039 100644 --- a/src/tpmc_match.c +++ b/src/tpmc_match.c @@ -267,9 +267,9 @@ static void populateSubPatternMatrixRowWithComponents(TpmcMatrix *matrix, arity, pattern->pattern->val.constructor->components->size); } for (int i = 0; i < arity; i++) { - setTpmcMatrixIndex(matrix, i, y, - pattern->pattern->val.constructor-> - components->entries[i]); + TpmcPattern *entry = + pattern->pattern->val.constructor->components->entries[i]; + setTpmcMatrixIndex(matrix, i, y, entry); } LEAVE(populateSubPatternMatrixRowWithComponents); } @@ -510,10 +510,11 @@ static void collectPathsBoundByPattern(TpmcPattern *pattern, break; case TPMCPATTERNVALUE_TYPE_BIGINTEGER: break; - case TPMCPATTERNVALUE_TYPE_CONSTRUCTOR: - collectPathsBoundByConstructor(pattern->pattern->val. - constructor->components, - boundVariables); + case TPMCPATTERNVALUE_TYPE_CONSTRUCTOR:{ + TpmcPatternArray *components = + pattern->pattern->val.constructor->components; + collectPathsBoundByConstructor(components, boundVariables); + } break; default: cant_happen("unrecognised type %d in collectPathsBoundByPattern", From df2cc1277b278270b92844ad945d22b386be059f Mon Sep 17 00:00:00 2001 From: Bill Hails Date: Sun, 3 Mar 2024 13:43:37 +0000 Subject: [PATCH 11/33] generate count functions for all singly self-referential linked lists --- src/anf_normalize.c | 29 ----------------- src/bytecode.c | 18 ----------- src/lambda_conversion.c | 22 ++----------- src/print_generator.c | 18 ----------- src/tc_analyze.c | 9 ------ tools/makeAST.py | 72 +++++++++++++++++++++++++++++++++++++---- 6 files changed, 68 insertions(+), 100 deletions(-) diff --git a/src/anf_normalize.c b/src/anf_normalize.c index 80b7dea..c115eb0 100644 --- a/src/anf_normalize.c +++ b/src/anf_normalize.c @@ -94,35 +94,6 @@ Exp *anfNormalize(LamExp *lamExp) { return normalize(lamExp, NULL); } -static int countAexpVarList(AexpVarList *list) { - int count = 0; - while (list != NULL) { - count++; - list = list->next; - } - return count; -} - -static int countAexpList(AexpList *list) { - int count = 0; - while (list != NULL) { - count++; - list = list->next; - } - return count; -} - -/* -static int countLetRecBindings(LetRecBindings *list) { - int count = 0; - while (list != NULL) { - count++; - list = list->next; - } - return count; -} -*/ - static Exp *normalize(LamExp *lamExp, Exp *tail) { ENTER(normalize); IFDEBUG(ppLamExp(lamExp)); diff --git a/src/bytecode.c b/src/bytecode.c index 8b2217b..363e8be 100644 --- a/src/bytecode.c +++ b/src/bytecode.c @@ -287,24 +287,6 @@ void writeCexpIf(CexpIf *x, ByteCodeArray *b) { LEAVE(writeCexpIf); } -static int countCexpCharCondCases(CexpCharCondCases *x) { - int val = 0; - while (x != NULL) { - val++; - x = x->next; - } - return val; -} - -static int countCexpIntCondCases(CexpIntCondCases *x) { - int val = 0; - while (x != NULL) { - val++; - x = x->next; - } - return val; -} - void writeCexpCharCondCases(int depth, int *values, int *addresses, int *jumps, CexpCharCondCases *x, ByteCodeArray *b) { diff --git a/src/lambda_conversion.c b/src/lambda_conversion.c index 26739ee..0c8d62a 100644 --- a/src/lambda_conversion.c +++ b/src/lambda_conversion.c @@ -63,26 +63,6 @@ static HashSymbol *dollarSubstitute(HashSymbol *original); # include "debugging_off.h" #endif -#define MAKE_COUNT_LIST(type) \ -static int count ## type (type *list) { \ - ENTER(count ## type); \ - int count = 0; \ - while (list != NULL) { \ - count++; \ - list = list->next; \ - } \ - LEAVE(count ## type); \ - return count; \ -} - -/* *INDENT-OFF* */ -MAKE_COUNT_LIST(LamLetRecBindings) -MAKE_COUNT_LIST(AstTypeList) -MAKE_COUNT_LIST(AstExpressions) -MAKE_COUNT_LIST(AstArgList) -MAKE_COUNT_LIST(AstCompositeFunction) -/* *INDENT-ON* */ - static bool inPreamble = true; // preamble is treated specially static bool preambleLocked = false; @@ -125,6 +105,8 @@ LamExp *lamConvertNest(AstNest *nest, LamContext *env) { result = newLamExp(LAMEXP_TYPE_TYPEDEFS, LAMEXP_VAL_TYPEDEFS(typeDefs)); } + if (hasLock) + preambleLocked = false; UNPROTECT(save); LEAVE(lamConvertNest); return result; diff --git a/src/print_generator.c b/src/print_generator.c index 88b44c9..7bb9c76 100644 --- a/src/print_generator.c +++ b/src/print_generator.c @@ -79,24 +79,6 @@ HashSymbol *makePrintName(char *prefix, char *name) { return res; } -static int countLamVarList(LamVarList *list) { - int res = 0; - while (list != NULL) { - list = list->next; - res++; - } - return res; -} - -int countLamList(LamList *list) { - int res = 0; - while (list != NULL) { - list = list->next; - res++; - } - return res; -} - static HashSymbol *printArgSymbol(void) { static HashSymbol *res = NULL; if (res == NULL) diff --git a/src/tc_analyze.c b/src/tc_analyze.c index 7cb2c4d..b622a6f 100644 --- a/src/tc_analyze.c +++ b/src/tc_analyze.c @@ -426,15 +426,6 @@ static TcType *analyzeSequence(LamSequence *sequence, TcEnv *env, TcNg *ng) { return type; } -static int countLamList(LamList *list) { - int i = 0; - while (list != NULL) { - i++; - list = list->next; - } - return i; -} - static LamApply *constructToApply(LamConstruct *construct) { ENTER(constructToApply); LamExp *constructor = diff --git a/tools/makeAST.py b/tools/makeAST.py index fd0075d..61c454a 100644 --- a/tools/makeAST.py +++ b/tools/makeAST.py @@ -85,6 +85,14 @@ def printMarkDeclarations(self): for entity in self.contents.values(): entity.printMarkDeclaration(self) + def printCountDeclarations(self): + for entity in self.contents.values(): + entity.printCountDeclaration(self) + + def printCountFunctions(self): + for entity in self.contents.values(): + entity.printCountFunction(self) + def printAccessDeclarations(self): for entity in self.contents.values(): entity.printAccessDeclarations(self) @@ -117,10 +125,6 @@ def printIteratorDeclarations(self): for entity in self.contents.values(): entity.printIteratorDeclaration(self) - def printCountDeclarations(self): - for entity in self.contents.values(): - entity.printCountDeclaration(self) - def printIteratorFunctions(self): for entity in self.contents.values(): entity.printIteratorFunction(self) @@ -312,7 +316,10 @@ def printAccessDeclarations(self, catalog): def printPushDeclaration(self, catalog): pass - def printPushFunction(selfself, catalog): + def printPushFunction(self, catalog): + pass + + def printCountFunction(self, catalog): pass def isEnum(self): @@ -375,6 +382,9 @@ def __init__(self, owner, name): self.owner = owner self.name = name + def isSimpleField(self): + return False; + def isSelfInitializing(self, catalog): return False @@ -424,6 +434,18 @@ def __init__(self, owner, name, typeName): self.typeName = typeName self.default = None + def isSimpleField(self): + return True + + def getName(self): + return self.name + + def getObj(self, catalog): + return catalog.get(self.typeName) + + def getObjName(self, catalog): + return self.getObj(catalog).getName() + def isSelfInitializing(self, catalog): obj = catalog.get(self.typeName) return obj.isSelfInitializing() @@ -1077,9 +1099,44 @@ def getTypeDeclaration(self): def getObjType(self): return ('objtype_' + self.getName()).upper() + def isSinglySelfReferential(self, catalog): + count = 0 + for field in self.fields: + if field.isSimpleField() and field.getObjName(catalog) == self.getName(): + count += 1 + return count == 1 + + def getSelfReferentialField(self, catalog): + for field in self.fields: + if field.isSimpleField() and field.getObjName(catalog) == self.getName(): + return field.getName() + raise Exception(f'cannot find self-referential field name for {self.getName()}') + def objTypeArray(self): return [ self.getObjType() ] + def getCountSignature(self): + myType = self.getTypeDeclaration() + myName = self.getName() + return f'int count{myName}({myType} x)' + + def printCountDeclaration(self, catalog): + if self.isSinglySelfReferential(catalog): + print(f'{self.getCountSignature()}; // SimpleStruct.printCountDeclaration') + + def printCountFunction(self, catalog): + if self.isSinglySelfReferential(catalog): + print(f'{self.getCountSignature()} {{ // SimpleStruct.printCountFunction') + selfRefField = self.getSelfReferentialField(catalog) + print(' int count = 0; // SimpleStruct.printCountFunction') + print(' while (x != NULL) { // SimpleStruct.printCountFunction') + print(f' x = x->{selfRefField}; // SimpleStruct.printCountFunction') + print(' count++;; // SimpleStruct.printCountFunction') + print(' } // SimpleStruct.printCountFunction') + print(' return count; // SimpleStruct.printCountFunction') + print('} // SimpleStruct.printCountFunction') + print('') + def getMarkSignature(self, catalog): myType = self.getTypeDeclaration() return "void mark{myName}({myType} x)".format(myName=self.getName(), myType=myType) @@ -1840,11 +1897,12 @@ def printSection(name): catalog.printGetDeclarations() catalog.printSetDeclarations() catalog.printIteratorDeclarations() - catalog.printCountDeclarations() printSection("defines") catalog.printDefines() printSection("access declarations") catalog.printAccessDeclarations() + printSection("count declarations") + catalog.printCountDeclarations() print("") print("#endif") @@ -1887,6 +1945,8 @@ def printSection(name): catalog.printGetFunctions() catalog.printSetFunctions() catalog.printIteratorFunctions() + printSection("count functions") + catalog.printCountFunctions() printSection("mark functions") catalog.printMarkFunctions() printSection("generic mark function") From 436fcad1a1ccb2a061466b80e5d3e620ed1639d2 Mon Sep 17 00:00:00 2001 From: Bill Hails Date: Sun, 3 Mar 2024 14:14:11 +0000 Subject: [PATCH 12/33] slightly neater output --- .indent.pro | 1 - Makefile | 3 ++- tools/makeAST.py | 7 ++----- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/.indent.pro b/.indent.pro index 49e7d3c..089edb1 100644 --- a/.indent.pro +++ b/.indent.pro @@ -13,7 +13,6 @@ --no-space-after-function-call-names --no-tabs --pointer-align-right ---preserve-mtime --preprocessor-indentation4 --space-after-for --space-after-if diff --git a/Makefile b/Makefile index 8e1d1c7..d7e6ed4 100644 --- a/Makefile +++ b/Makefile @@ -138,7 +138,8 @@ profile: all valgrind --tool=callgrind ./$(TARGET) indent: .typedefs .indent.pro - indent `cat .typedefs | sort -u | xargs` -T bigint_word -T BigInt -T IntegerBinOp -T Control -T Stack -T Env -T Snapshot -T Kont -T ValueList -T Clo -T Fail -T Vec -T ProtectionStack -T HashSymbol -T hash_t -T Header -T PmModule -T HashTable -T byte -T word -T ByteCodes -T ByteCodeArray -T Value -T FILE src/*.[ch] + indent `cat .typedefs | sort -u | xargs` -T bigint_word -T BigInt -T IntegerBinOp -T Control -T Stack -T Env -T Snapshot -T Kont -T ValueList -T Clo -T Fail -T Vec -T ProtectionStack -T HashSymbol -T hash_t -T Header -T PmModule -T HashTable -T byte -T word -T ByteCodes -T ByteCodeArray -T Value -T FILE src/*.[ch] generated/*.[ch] + rm -f src/*~ generated/*~ .typedefs: .generated diff --git a/tools/makeAST.py b/tools/makeAST.py index 61c454a..a2e4688 100644 --- a/tools/makeAST.py +++ b/tools/makeAST.py @@ -642,6 +642,7 @@ def printTypedef(self, catalog): print(f'typedef struct {myName} {{ // SimpleHash.printTypedef') print(' struct HashTable wrapped; // SimpleHash.printTypedef') print(f'}} {myName}; // SimpleHash.printTypedef') + print('') def printCopyField(self, field, depth, prefix=''): myConstructor = self.getConstructorName() @@ -685,11 +686,7 @@ def printNewFunction(self, catalog): print('}') print('') print(f'{decl} {{ // SimpleHash.printNewFunction') - print(f' return ({myName} *)newHashTable( // SimpleHash.printNewFunction') - print(f' {size}, // SimpleHash.printNewFunction') - print(f' {markFn}, // SimpleHash.printNewFunction') - print(f' {printFn} // SimpleHash.printNewFunction') - print(' ); // SimpleHash.printNewFunction') + print(f' return ({myName} *)newHashTable({size}, {markFn}, {printFn});// SimpleHash.printNewFunction') print('}') print('') From 32869e1b3db13b31a870bbf3027d957a5140bda2 Mon Sep 17 00:00:00 2001 From: Bill Hails Date: Sun, 3 Mar 2024 14:54:43 +0000 Subject: [PATCH 13/33] generate count functions for arrays --- tools/makeAST.py | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/tools/makeAST.py b/tools/makeAST.py index a2e4688..ce648c3 100644 --- a/tools/makeAST.py +++ b/tools/makeAST.py @@ -597,11 +597,11 @@ def getIteratorDeclaration(self, catalog): def printIteratorDeclaration(self, catalog): decl = self.getIteratorDeclaration(catalog) - print(f'{decl}; // SimpleHask.printIteratorDeclaration') + print(f'{decl}; // SimpleHash.printIteratorDeclaration') def printIteratorFunction(self, catalog): decl = self.getIteratorDeclaration(catalog) - print(f'{decl} {{ // SimpleHask.printIteratorFunction') + print(f'{decl} {{ // SimpleHash.printIteratorFunction') if self.entries is None: print(' return iterateHashTable((HashTable *)table, i, NULL);') else: @@ -632,9 +632,10 @@ def printGetFunction(self, catalog): def printCountDeclaration(self, catalog): myName = self.getName() myType = self.getTypeDeclaration() - print(f'static inline int count{myName}({myType} table) {{') - print(' return ((HashTable *)table)->count;') - print('}') + print(f'static inline int count{myName}({myType} table) {{ // SimpleHash.printCountDeclaration') + print(' return ((HashTable *)table)->count; // SimpleHash.printCountDeclaration') + print('} // SimpleHash.printCountDeclaration') + print('') def printTypedef(self, catalog): self.noteTypedef() @@ -738,16 +739,20 @@ def printPrintField(self, field, depth, prefix=''): def printAccessDeclarations(self, catalog): if self.dimension == 2: print(f"static inline {self.entries.getTypeDeclaration(catalog)} get{self.getName()}Index({self.getTypeDeclaration()} obj, int x, int y) {{ // SimpleArray.printAccessDeclarations") + print("#ifdef SAFETY_CHECKS // SimpleArray.printAccessDeclarations"); print(" if (x >= obj->width || y >= obj->height || x < 0 || y < 0) { // SimpleArray.printAccessDeclarations"); print(' cant_happen("2d matrix bounds exceeded"); // SimpleArray.printAccessDeclarations') print(" }") + print("#endif // SimpleArray.printAccessDeclarations"); print(" return obj->entries[x + y * obj->width]; // SimpleArray.printAccessDeclarations") print("} // SimpleArray.printAccessDeclarations") print("") print(f"static inline void set{self.getName()}Index({self.getTypeDeclaration()} obj, int x, int y, {self.entries.getTypeDeclaration(catalog)} val) {{ // SimpleArray.printAccessDeclarations") + print("#ifdef SAFETY_CHECKS // SimpleArray.printAccessDeclarations"); print(" if (x >= obj->width || y >= obj->height || x < 0 || y < 0) { // SimpleArray.printAccessDeclarations"); print(' cant_happen("2d matrix bounds exceeded"); // SimpleArray.printAccessDeclarations') print(" } // SimpleArray.printAccessDeclarations") + print("#endif // SimpleArray.printAccessDeclarations"); print(" obj->entries[x + y * obj->width] = val; // SimpleArray.printAccessDeclarations") print("} // SimpleArray.printAccessDeclarations") @@ -909,6 +914,17 @@ def getPrintSignature(self, catalog): def getCtype(self, astType, catalog): return f"{astType} *" + def printCountDeclaration(self, catalog): + myName = self.getName() + myType = self.getTypeDeclaration() + print(f'static inline int count{myName}({myType} x) {{ // SimpleArray.printCountDeclaration') + if self.dimension == 1: + print(' return x->size; // SimpleArray.printCountDeclaration') + else: + print(' return x->width * x->height; // SimpleArray.printCountDeclaration') + print('} // SimpleArray.printCountDeclaration') + print('') + def getExtraCmpFargs(self, catalog): extra = [] for name in self.extraCmpArgs: From 4a7f6dae158baf54e8f3d9fc88ae28c2df34bcad Mon Sep 17 00:00:00 2001 From: Bill Hails Date: Wed, 6 Mar 2024 18:14:45 +0000 Subject: [PATCH 14/33] various tiny simplifications --- src/lambda_conversion.c | 52 ++++++++++++++--------------------------- src/print_generator.c | 1 + src/print_generator.h | 1 - 3 files changed, 18 insertions(+), 36 deletions(-) diff --git a/src/lambda_conversion.c b/src/lambda_conversion.c index 0c8d62a..811eac0 100644 --- a/src/lambda_conversion.c +++ b/src/lambda_conversion.c @@ -49,10 +49,10 @@ static LamTypeDefList *collectTypeDefs(AstDefinitions *definitions, static LamTypeConstructor *collectTypeConstructor(AstTypeConstructor *typeConstructor, LamType *type, int size, - int index, bool hasFields, + int index, bool needsVec, LamContext *env); static void collectTypeInfo(HashSymbol *symbol, LamTypeConstructor *type, - bool someoneHasFields, int enumCount, int index, + bool needsVec, int enumCount, int index, int arity, LamContext *env); static LamTypeConstructorArgs *convertAstTypeList(AstTypeList *typeList); static HashSymbol *dollarSubstitute(HashSymbol *original); @@ -155,15 +155,6 @@ static LamLetRecBindings *convertFuncDefs(AstDefinitions *definitions, return this; } -static int countTypeBodies(AstTypeBody *typeBody) { - int count = 0; - while (typeBody != NULL) { - count++; - typeBody = typeBody->next; - } - return count; -} - static LamTypeArgs *convertTypeSymbols(AstTypeSymbols *symbols) { if (symbols == NULL) return NULL; @@ -278,11 +269,11 @@ static LamTypeConstructorArgs *convertAstTypeList(AstTypeList *typeList) { } static void collectTypeInfo(HashSymbol *symbol, LamTypeConstructor *type, - bool someoneHasFields, int enumCount, int index, + bool needsVec, int enumCount, int index, int arity, LamContext *env) { ENTER(collectTypeInfo); LamTypeConstructorInfo *info = - newLamTypeConstructorInfo(type, someoneHasFields, arity, enumCount, + newLamTypeConstructorInfo(type, needsVec, arity, enumCount, index); int save = PROTECT(info); addToLamContext(env, symbol, info); @@ -294,7 +285,7 @@ static LamTypeConstructor *collectTypeConstructor(AstTypeConstructor *typeConstructor, LamType *type, int enumCount, int index, - bool someoneHasFields, + bool needsVec, LamContext *env) { int nargs = countAstTypeList(typeConstructor->typeList); LamTypeConstructorArgs *args = @@ -303,8 +294,8 @@ static LamTypeConstructor *collectTypeConstructor(AstTypeConstructor LamTypeConstructor *lamTypeConstructor = newLamTypeConstructor(typeConstructor->symbol, type, args); PROTECT(lamTypeConstructor); - collectTypeInfo(typeConstructor->symbol, lamTypeConstructor, - someoneHasFields, enumCount, index, nargs, env); + collectTypeInfo(typeConstructor->symbol, lamTypeConstructor, needsVec, + enumCount, index, nargs, env); UNPROTECT(save); return lamTypeConstructor; } @@ -313,8 +304,8 @@ static LamTypeDef *collectTypeDef(AstTypeDef *typeDef, LamContext *env) { LamType *type = convertUserType(typeDef->userType); int save = PROTECT(type); AstTypeBody *typeBody = typeDef->typeBody; - bool hasFields = typeHasFields(typeBody); - int enumCount = countTypeBodies(typeBody); + bool needsVec = typeHasFields(typeBody); + int enumCount = countAstTypeBody(typeBody); int index = 0; LamTypeConstructorList *lamTypeConstructorList = NULL; int save2 = PROTECT(type); @@ -324,7 +315,7 @@ static LamTypeDef *collectTypeDef(AstTypeDef *typeDef, LamContext *env) { type, enumCount, index, - hasFields, + needsVec, env); int save3 = PROTECT(lamTypeConstructor); lamTypeConstructorList = @@ -448,24 +439,15 @@ static HashSymbol *dollarSubstitute(HashSymbol *symbol) { } #define CHECK_ONE_ARG(name, args) do { \ - if ((args) == NULL) { \ - cant_happen("expected 1 arg in " #name ", got 0"); \ - } \ - if ((args)->next != NULL) { \ - cant_happen("expected 1 arg in " #name ", got > 1"); \ - } \ + int count = countLamList(args); \ + if (count != 1) \ + cant_happen("expected 1 arg in " #name ", got %d", count); \ } while(0) #define CHECK_TWO_ARGS(name, args) do { \ - if ((args) == NULL) { \ - cant_happen("expected 2 args in " #name ", got 0"); \ - } \ - if ((args)->next == NULL) { \ - cant_happen("expected 2 args in " #name ", got 1"); \ - } \ - if ((args)->next->next != NULL) { \ - cant_happen("expected 2 args in " #name ", got > 2"); \ - } \ + int count = countLamList(args); \ + if (count != 2) \ + cant_happen("expected 2 args in " #name ", got %d", count); \ } while(0) static LamExp *makeUnaryOp(LamUnaryOp opCode, LamList *args) { @@ -614,7 +596,7 @@ static LamExp *convertFunCall(AstFunCall *funCall, LamContext *env) { UNPROTECT(save); return result; } - // see if it's a type constructor we can inline FIXME - or a primitive + // see if it's a type constructor we can inline result = inlineConstructor(symbol, args, env); if (result != NULL) { UNPROTECT(save); diff --git a/src/print_generator.c b/src/print_generator.c index 7bb9c76..961217a 100644 --- a/src/print_generator.c +++ b/src/print_generator.c @@ -446,6 +446,7 @@ static LamLetRecBindings *makePrintFunction(LamTypeDef *typeDef, LamContext *env, bool inPreamble) { if (inPreamble && isListType(typeDef->type)) { + // print$list is hand-coded in the preamble return next; } else { return makePrintTypeFunction(typeDef, env, next); diff --git a/src/print_generator.h b/src/print_generator.h index 1b2109e..89dccc6 100644 --- a/src/print_generator.h +++ b/src/print_generator.h @@ -29,6 +29,5 @@ LamExp *makeSymbolExpr(char *name); LamExp *makePrintInt(); LamExp *makePrintChar(); HashSymbol *makePrintName(char *prefix, char *name); -int countLamList(LamList *list); #endif From 2cbc3972cede4de9cc6b442e4ab4c52b07dfdcf6 Mon Sep 17 00:00:00 2001 From: Bill Hails Date: Wed, 6 Mar 2024 18:53:26 +0000 Subject: [PATCH 15/33] grabbed ENV.md from env-3 --- docs/ENV.md | 475 +++++++++++++++++++++++++++++++++++++++++++ docs/Overview.drawio | 121 +++++++++++ 2 files changed, 596 insertions(+) create mode 100644 docs/ENV.md create mode 100644 docs/Overview.drawio diff --git a/docs/ENV.md b/docs/ENV.md new file mode 100644 index 0000000..58c36cc --- /dev/null +++ b/docs/ENV.md @@ -0,0 +1,475 @@ +# Environments + +Various approaches to having namespaced environments. + +## Environments as Namespaces + +By elevating environments to first-class data types we can re-use existing +code to achieve encapsulation and namespaces. + +However this proves very difficult to reconcile with fast lexical +adressing, two environments with the same apparent prototype can still +differ in the order of their bindings and hence the lexical addresses of +their components, a variable access could not then be correctly annotated +for multiple use-cases. + + +## Namespaces Only + +As an alternative to fully first-class environments we could look at +`env` declarations purely as namespaces, that is the names of envs are +not variables but constant names to be used literally. This is certainly +simpler, but the semantics are a bit wooly, so how would it work? + +The `.` operator would evaluate its rhs in the context of the namespace +on the lhs, like `myns.doSomething(arg)`. The dot operator would have to +have higher precedence than even function calls, so that would parse as +`(myns.doSomething)(arg)`. Bytecode might then be something like + +``` +| ..arg.. | SAVENV | myns | SETENV | VAR[n][n] | SWAP | RESTORENV | APPLY | +``` + +I'm not sure I like the save and restore because we don't currently have +an environment stack, and we'd need Forth-level stack twiddling to use +the existing stack (i.e. the `VAR` lookup would leave its result top of +stack hence the need for a SWAP bytecode or similar). + +> Future self: using the existing stack turns out to be fine. + +The new `getenv` internal construct pushes the current environment on +the top of the stack, where it can be bound to a variable `myns` in the +normal way. `myns` in the bytecode above just becomes a var lookup. + +What about type checking? Again if `myns` is bound to a `TcEnv` during +type checking, that env can be used to validate the rhs of the dot +operator. + +Any other holes in this idea? ANF conversion is purely local transforms +that shouldn't be affected, desugaring likewise. + +### Printing Again + +The `print` construct fails in this scenario though. If an env declares a +`typedef` and return data of that type, then for example + +``` +print(a.returnThing()) +``` + +will compole to + +```scheme +(print$Thing (dot a (returnThing))) +``` + +and `print$thing` is not in scope. Error. What we want print to compile +to instead is + +```scheme +((dot a print$Thing) (dot a (returnThing))) +``` + +This can be made to work if types are annotated with their scopes. which +leads to... + +### Scoped Types + +Scoped types are necessary in any case, otherwise two environments could +both declare the same type name for different types and those types +would unify incorrectly. So we'll need types to unify on their scopes +too. For that reason scopes need to be canonical. + +It works to treat canonical scopes equivalently to a file system with +a root `/`, the difference being that we don't allow relative paths, +only absolute ones. + +It will also pay to keep the syntax distinct in discussions, using +`/a/b/c` to mean a canonical scope and restrict `a.b.c` to mean lookup in +the surface language, which has very different semantics. To illustrate, +after: + +``` +env a { + env b { + } +} +env c { + d +} +``` + +...the expression `a.b.c.d` is valid at the top level: `a` is found +at top, `b` is found in `a`, but when `c` is not found in `b` search +proceeds back to `a` then to the root where `c` is located, thence `d`, +so in this example `a.b.c.d` resolves to `/c/d`. + +Before proceeding, there's a problem here: + +``` +env a { + env b { + env c { + } + } +} +env c { + d +} +``` + +in this case `a.b.c.d` would not resolve because `c` is found in `b` +and will not be searched for a second time. + +we could solve this with backtracking (compile time so probably ok) +but the semantics are still not great, maybe better to leave as is and +fail to resolve, after all given the above `a.b.c.d` is a pretty silly +thing to do. + +Anyway assuming we can always resolve valid type scopes to a canonical +form, the print compiler will need the type, as before, plus the current +canonical scope. For example + +``` +env a { + env b { + typedef T1 ... + fn getT1() {...} + } + ... + print(b.getT1()) +} +``` + +The print compiler will get a type `/a/b/T1` and a current scope `/a` +so will resolve to: + +```scheme +((dot b print$T1) (dot b (getT1))) +``` + +by removing the common prefix. + +This should work fine with `extends` whaen that's implemented: + +``` +env complex extends math { ... } +``` + +provides an initial `/math` scope for processing `complex`. + +Another problem with this though, typedefs from within function bodies +won't be resolvable in this way, or even at all since the `print$thing` +functions won't even exist after the function exits. Maybe we only allow +typedefs and envs within other envs or at the top level? + +Since that seems overly restrictive, let's try another approach. + +### Named vs. Anonymous Scopes + +Suppose we make a distinction between `env`s being "named scopes" and +other types of anonymous nests (function bodies etc.) as being "anonymous +scopes", then we can simply impose the restiction that user-defined types +cannot escape anonymous scopes. That way we can continue to use typedefs +within function bodies, but functions defining such types can only use +them internally and not return values of those types. types defined within +envs are accessible outside of those envs if they are qualified by the +path to that env (which cannot cross the boundary of an anonymous scope). + +All types can remain fully qualified by a scope, but canonical scopes +can make use of some internally constructed pseudo-root to indicate +they are not top-level. A possible nomenclature might be `$/a/b/c` meaning +`a` is an env whose parent is the closest enclosing anonymous scope. + +Trial: + +``` +env a { + typedef T1 ... // /a/T1 + env b { + typedef T2 ... // /a/b/T2 + } + fn f1 () { // begin anonymous scope + typedef T3 ... // $/T3 + T3 // ok $/T3 + b.T2 // ok /a/b/T2 + T1 // ok /a/T1 + } + T1 // ok /a/T1 + b.T2 // ok /a/b/T2 + T3 // not ok +} +``` + +This looks like it could be made to work, but will need some formalizing. +In particular the error case, if `T3` is allowed to leak out of +`f1` then its scope cannot just be re-interpreted as a new nearest +enclosing anonymous scope, so maybe each anonymous scope needs a unique +identifier? or we trap the leak and raise an error. Trapping the leak +is too restrictive: if we declare a type inside a function and then +map over a list of that type within the function that should be fine, +but the type must be leaked to `map` it's just that map doesn't care as +long as the types of its arguments match `(a -> b) -> list(a) -> list(b)`. + +Since the type checker we've already decided will be passing around a +current canonical scope, we might just use the machine address of the +nest as the current scope, or generate a symbol on the fly with a qualifying +`$` to say it's anonymous. Then it's unifiable within the current scope +but not outside of it. + +so assume each anonymous nest generates a new id, and then all canonical +paths are root based. We've identified two "leaking" scenarios so far: + +1. Returning a value from a function of a type defined in that function. +2. Passing a value from a function, of a type defined in that function, + to another polymorphic function. + +The first should cause an error if that type is used in a non-polymorphic +way, the second should be ok. + +``` +env a { + fn b() { + let + typedef T1 ... // /a/$nnn/T1 + fn c (t1) { ... } // /a/$nnn/T1 -> int + in + map(c [t1, t1, t1]) // returns list of int + } +} +``` + +`map` should get `(/a/$nnn/T1 -> int) -> /list(/a/$nnn/T1) -> /list(int)` +which will unify fine even outside of the body of `fn b`. + +Because the type checker is passing around the current scope, `print` can +compare that with the scope of a type `T1` to determine if the `print$T1` +function is in scope or not. If the type is in scope it will use the +generated printer, otherwise fallback to a generic default `putv`.` + +`print` needs the scope in any case to "trim" the canonical scope to an +env path, and if there are no anonymous ids left in this trimmed path then +`print` knows the `print$T1` function is accessible. + +So to nail the semantics, scopes are linked lists, the root of the +scope is the tail of the list, so in `env a { env b { env c { x } } }` +the scope of `x` is `c=>b=>a=>/`. Having got that out of the way lets +tabulate some examples using the following structure: + +``` +T1 +env a { + T2 + fn f1 { + T3 + } + env b { + T4 + fn f2 { + T5 + } + env c { + T6 + fn f3 { + T7 + } + } + } +} +env d { + T8 + fn f4 { + T9 + } +} + +``` + +| current scope | type scope | relative scope | accessible | notes | +| ------------- | ------------------- | -------------- | ---------- | ----- | +| `/` | `T1 /` | `T1` | Y | both global | +| `/` | `T2 a=>/` | `a.T2` | Y | | +| `/` | `T3 f1=>a=>/` | `a.f1.T3` | N | relative contains anonymous scope | +| `/` | `T4 b=>a=>/` | `a.b.T4` | Y | | +| `/` | `T5 f2=>b=>a=>/` | `a.b.f2.T5` | N | | +| `/` | `T6 c=>b=>a=>/` | `a.b.c.T6` | Y | | +| `/` | `T7 f3=>c=>b=>a=>/` | `a.b.c.f3.T7` | N | | +| `/` | `T8 d=>/` | `d.T8` | Y | same as T2 | +| `/` | `T9 f4=>d=>/` | `d.f4.T9` | N | same as T3 | +| `a=>/` | `T1 /` | `T1` | Y | parent scope | +| `a=>/` | `T2 a=>/` | `T2` | Y | same scope | +| `a=>/` | `T3 f1=>a=>/` | `f1.T3` | N | relative contains anonymous scope | +| `a=>/` | `T4 b=>a=>/` | `b.T4` | Y | | +| `a=>/` | `T5 f2=>b=>a=>/` | `b.f2.T5` | N | | +| `a=>/` | `T6 c=>b=>a=>/` | `b.c.T6` | Y | | +| `a=>/` | `T7 f3=>c=>b=>a=>/` | `b.c.f3.T7` | N | | +| `a=>/` | `T8 d=>/` | `d.T8` | Y | parent scope | +| `a=>/` | `T9 f4=>d=>/` | `d.f4.T9` | N | parent scope | +| `f1=>a=>/` | `T1 /` | `T1` | Y | parent scope | +| `f1=>a=>/` | `T2 a=>/` | `T2` | Y | same scope | +| `f1=>a=>/` | `T3 f1=>a=>/` | `T3` | Y | anonymous scope pruned | +| `f1=>a=>/` | `T4 b=>a=>/` | `b.T4` | Y | | +| `f1=>a=>/` | `T5 f2=>b=>a=>/` | `b.f2.T5` | N | different functions | +| `f1=>a=>/` | `T6 c=>b=>a=>/` | `b.c.T6` | Y | | +| `f1=>a=>/` | `T7 f3=>c=>b=>a=>/` | `b.c.f3.T7` | N | | +| `f1=>a=>/` | `T8 d=>/` | `d.T8` | Y | parent scope | +| `f1=>a=>/` | `T9 f4=>d=>/` | `d.f4.T9` | N | parent scope | +| `b=>a=>/` | `T1 /` | `T1` | Y | parent scope | +| `b=>a=>/` | `T2 a=>/` | `T2` | Y | same scope | +| `b=>a=>/` | `T3 f1=>a=>/` | `f2.T3` | N | anonymous scope pruned | +| `b=>a=>/` | `T4 b=>a=>/` | `T4` | Y | | + +etc. + +Obviously the relative scope is generated by comparing the current +scope with the type scope and removing any common roots. Then if the +result contains any anonymous components the type is not accessible +from the current scope, as far as printing is concerned (the generated +`print$type` functions are not accessible to the print compiler). If the +types and therefore their generated print functions are acccessible, the +print compiler need only prefix the print function with the calculated +relative scope. Otherwise it uses the generic `print$` function. + +### Algorithm to Calculate Relative Scope + +Easiest is just to reverse the scopes then walk them from tail to head. +We'll have tuples at some point so let's just use them here, a scope +element is a tuple of a string and a bool (anonymous flag). A scope is +a list of elements. + +``` +fn relativeScope { + ([], []) { [] } + (#(v, _) @ sc, #(v, _) @ st) { relativeScope(sc, st) } + (_, st) { st } +} +``` + +Try it on a few examples + +| sc | st | result | +| --- | --- | -------| +| / | / | / | +| / | a | a | +| / | a.b | a.b | +| / | b | b | +| a | / | / | +| a | a | / | +| a | a.b | b | +| a | b | b | +| a.b | / | / | +| a.b | a | / | +| a.b | a.b | / | + +## More Problems + +Consider + +``` +env a { + env b { + T1 + } +} +env b { + T1 +} +``` + +`a.b.T1` resolves to `b.T1` in `a`, but so does `b.T1`, so the whole +relative paths idea may be dead in the water. But only `print` uses +these relative paths, can it use absolute ones? or, for efficiency, +have a global root env that is hidden (illegal var name) but can be +pruned to a relative path as with any other? None of the above changes, +except that the root is an explicit component rather than just nil. + +We might even support it in the language, use a leading '`.`' to signify +an absolute path, that way in the above, code inside `.a` could explicitly +refer to code in `.b`, distinct from `.a.b` which it could continue to +refer to as just `b`. + +If we use `$` to signify the root then `$.b` in context `$.a.b` would +still get pruned to `b` so that doesn't work either. + +Of course we don't have to prune, `print` would still work if all +of its paths were absolute, but we'd loose the ability to check for +inaccessible scopes, and actually `print` relies on relative paths +to avoid impossible lookups on those anonymous scopes so it wouldn't +work. + +Another option, this might just work, rename environments to all have +unique names, or otherwise tag them with some unique id. Some sort +of scoping rules would be needed to rewrite explicit environment +references, but the print compiler would just directly use the unique +names. In fact the unique names could just be their absolute paths +or some concatenation of them. That then removes the need for a global +env to qualify them, top-level `.b` is just `b`, but `.a.b` becomes +something like `.a.a/b` and within `.a`, `b` is relatively `a/b`. + +### TODO, then + +1. rename environments to reflect their scope and make them globally + unique. +2. rewrite explicit environment lookups to use these qualified names. +3. type-checker maintains current environment context and passes it to + the print compiler, as well as using it to qualify the context of + each type (constructor). + +## Environments as Dispatch Functions + +Another possibility is to translate an environment into a dispatch +function returning the components of the environment. + +This promises less effort because the generated lambda calculus will not +need to be extended to support environments explicitly, and therefore +nothing downstream of it will need those extensions either. There is +the adiitional overhead of a lookup and return to access an environment +component, but that might be worth the decrease in complexity. + +The problem is that such a dispatch function, which must return arbitrary +types, can not be naively type-checked. We have to either type-check it +specially, or propagate the environment concept into the lambda form, +rewriting it to a dispatch after type checking. This might still be +worthwhile. + +Anyway the transformations are quite straightforward, for example + +``` +let + env a { + typedef color { red | green | blue } + fn add1(x) { 1 + x } + } +in + a.add1(2) +``` + +might generate something like: + +```scheme +(letrec ((a + (letrec ((print$color ...) + (add1 (lambda (x) (+ 1 x)))) + (lambda (selector) ;; returned dispatch function 'a' + (match selector + ((0) print$color) + ((1) add1)))))) + ((a 1) 2)) +``` + +Note that any generated `print$` functions are also exported, and we +make use of the existing `match` construct for fast O(1) lookup, safe +because we know the number of elements in the environment. + +Chained lookup also works, so `a.b.c(x)` becomes something like `(((a 0) +1) x)` + +It would be preferable to typecheck the dispatcher specially but that +might be just as difficult or more so than typechecking the environment +then transforming it. It would be less likely to be wrong though. + +Also it's not yet clear how this might work if we plan to implement the +`extends` attribute of environments, which is likely a requirement for +any really useful language. + +Anyway, food for thought, and maybe there's a hybrid approach. diff --git a/docs/Overview.drawio b/docs/Overview.drawio new file mode 100644 index 0000000..9f05d05 --- /dev/null +++ b/docs/Overview.drawio @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From b13464dae189ac66308ad0468d723612b883570c Mon Sep 17 00:00:00 2001 From: Bill Hails Date: Fri, 8 Mar 2024 17:46:50 +0000 Subject: [PATCH 16/33] more thoughts on env --- docs/ENV.md | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/docs/ENV.md b/docs/ENV.md index 58c36cc..f128836 100644 --- a/docs/ENV.md +++ b/docs/ENV.md @@ -473,3 +473,52 @@ Also it's not yet clear how this might work if we plan to implement the any really useful language. Anyway, food for thought, and maybe there's a hybrid approach. + +Returning to this, actually there is a way to get a dispatch function +past the type-checker, if we declare a type that contains all possible +arguments and another type that contains all popssible result types, +for example: + +``` +let + env a { + fn map { + (_, []) { [] } + (f, h @ t) { f(h) @ map(f, t) } + } + fn fact { + (0) { 1 } + (n) { n * fact(n - 1) } + } + } +in + a.factorial(5) +``` +becomes something like +``` +let + typedef a$args(#f, #u) { a$map$args(#f, list(#t)) | a$fact$args(int) } + typedef a$results(#u) { a$map$result(list(#u)) | a$fact$result(int) } + fn a$dispatch(args) { + let + fn map { + (_, []) { [] } + (f, h @ t) { f(h) @ map(f, t) } + } + fn fact { + (0) { 1 } + (n) { n * fact(n - 1) } + } + in + switch(args) { + (a_map_args(f, u)) { a_map_result(map(f, u)) } + (a_fact_args(n) { a_fact_result(fact(n)) } + } + } +in + switch (a$dispatch(a$fact$args(5))) { + (a$fact$result(n)) { n } + } +``` +That might just work but I'm not sure I like it. + From 5a29f461640d355a3811561818c10e8928293c0d Mon Sep 17 00:00:00 2001 From: Bill Hails Date: Sat, 9 Mar 2024 13:39:52 +0000 Subject: [PATCH 17/33] minor clean-up --- Makefile | 13 +++--- fn/qsort.fn | 125 +++++++++++++++++++++++++++++++++++++++++++--------- src/step.c | 2 +- 3 files changed, 110 insertions(+), 30 deletions(-) diff --git a/Makefile b/Makefile index d7e6ed4..87f7637 100644 --- a/Makefile +++ b/Makefile @@ -9,13 +9,12 @@ PROFILING=-pg OPTIMIZING=-O2 DEBUGGING=-g -# CCMODE = $(PROFILING) -# CCMODE = $(OPTIMIZING) CCMODE = $(DEBUGGING) CC=cc -Wall -Wextra -Werror $(CCMODE) LAXCC=cc -Werror $(CCMODE) PYTHON=python3 +MAKEAST=$(PYTHON) ./tools/makeAST.py EXTRA_YAML=$(filter-out src/primitives.yaml, $(wildcard src/*.yaml)) EXTRA_C_TARGETS=$(patsubst src/%.yaml,generated/%.c,$(EXTRA_YAML)) @@ -68,19 +67,19 @@ $(TARGET): $(MAIN_OBJ) $(ALL_OBJ) include $(ALL_DEP) $(EXTRA_C_TARGETS): generated/%.c: src/%.yaml tools/makeAST.py src/primitives.yaml | generated - $(PYTHON) tools/makeAST.py $< c > $@ || (rm -f $@ ; exit 1) + $(MAKEAST) $< c > $@ || (rm -f $@ ; exit 1) $(EXTRA_H_TARGETS): generated/%.h: src/%.yaml tools/makeAST.py | generated - $(PYTHON) tools/makeAST.py $< h > $@ || (rm -f $@ ; exit 1) + $(MAKEAST) $< h > $@ || (rm -f $@ ; exit 1) $(EXTRA_OBJTYPES_H_TARGETS): generated/%_objtypes.h: src/%.yaml tools/makeAST.py src/primitives.yaml | generated - $(PYTHON) tools/makeAST.py $< objtypes_h > $@ || (rm -f $@ ; exit 1) + $(MAKEAST) $< objtypes_h > $@ || (rm -f $@ ; exit 1) $(EXTRA_DEBUG_H_TARGETS): generated/%_debug.h: src/%.yaml tools/makeAST.py src/primitives.yaml | generated - $(PYTHON) tools/makeAST.py $< debug_h > $@ || (rm -f $@ ; exit 1) + $(MAKEAST) $< debug_h > $@ || (rm -f $@ ; exit 1) $(EXTRA_DEBUG_C_TARGETS): generated/%_debug.c: src/%.yaml tools/makeAST.py src/primitives.yaml | generated - $(PYTHON) tools/makeAST.py $< debug_c > $@ || (rm -f $@ ; exit 1) + $(MAKEAST) $< debug_c > $@ || (rm -f $@ ; exit 1) .generated: $(EXTRA_TARGETS) $(TMP_H) touch $@ diff --git a/fn/qsort.fn b/fn/qsort.fn index b877f95..d6680c2 100644 --- a/fn/qsort.fn +++ b/fn/qsort.fn @@ -1,29 +1,110 @@ -// naive un-optimised quicksort implementation to -// demonstrate the principle, see qqsort.fn for -// an optimised version. +// qsort is a naive un-optimised quicksort implementation to +// demonstrate the principle, qqsort is an optimised version. let - unsorted = "rhrtgefewhgjtyjyuosfsfswfgikpzxxvcbfvwfh"; + unsorted = "kgimtseettepmupybbbmplgntqzutrfxqarkivirlbjqjigntslfewhnjouuyiepnswymkfpyovclntwb" + "mhngufnoeidjfmhxxaqmqiaoodslwlwwnzxtdxawnfxbiesjtdwmrzkbdozzyppmdyzhvyhfadldkflw" + "iwvmfutfeckzsqulxlenvpwpbqdjwxpphhtyeuojmvmhgwcisxevzlvbtnobaaokqbutzqumbzlgqwqs" + "ludnrygnynsqcvjekjouyyplgyzlhlsbakaknjauctsspolsvifpwrklfxjfbxrnkecgmypfkbxonkus" + "uzigleakcrnqhktvjonlfiuoeoupuwdtzyytsmggyspdoswafjvceqyzgtksocdhszgybbrrivirlcgo" + "zvxgtvtxgyuukntggimfsoprufwmdngqkabxolitehdjbiqhdjexiaojatkhdjdcpckbxdxwfocqjchi" + "jeylcyhoxnywikniqzpqeeqtucengrvgbbntwmvyeoddjxlgqablttpyrmxlckrvstwmvmfcvmbskciv" + "vsjlchmoczdnbczvznnkiaabonyiqvjmbiyeddetcczprvjfmhmshxmknhonxyxgbgpawkahqbknbqpa" + "rgbnnunwgxphhlvedlyazkfzavezdtlfefpvjiooocpwspyalpahadximvaauocirfgpijbhqskcuuyn" + "vcvtndifklhczerlvjpfpjhnkxxprrsktdfnrrmoypigecxbkzxflgtmdxxzfvdvesewzqotfdlqfibz" + "kchndafnmxirrruoluwghokrgadfanokngfgrwnuxboualnlhxmighxpwfhcvsdgyiryiehzsaqpelnh" + "mzbejngybaqnnwthmxohakvwulpyzsdltquyyxfjtmfrkajmroebudshflggonmhmqahdvdmytvalcdi" + "gjqzsiefihwiihqwuvptripgpzwwbjkqrqwmacsjoqbphilfrkuaqbcqvedwkpmbmxdclajloiimciya" + "trpuhddbpknmkydzxpxqbmiyugulmxxaffpqlurwechzjgsgzrivnzsdbihytchqxvderrjxsoilgyzi" + "zpumoaexhovuadssebduwakznwigstaxgcjixnwfplffmdmpnkgtnrcbkeefpgbdxpjxlrxoiabhhzfn" + "lnshiwszijzfnstudgnqnvvqyshcnekqokcftgiqirhfgxvttijoohfaaapgdrxjiqwmbhwcvudlcexq" + "ybceknreincfokgvoznyfymbjfihngowqecfrwyiwcoawpxnwmxjqdjfsswewbparjwvgmqoqkqsltop" + "vdbvfdwuzgyymdfwxbwccsyzqrvgwgwbmjxqwdcpszcvgghjmwbdsiyrruoparniylkdwxyfsosxzfwz" + "nazzvorretnjpvfndbepurvghnzzzsmoffqoqqcibiblqwsjbjakclgwuuirisihetsykmzhtvrkrqcn" + "paupfvwtyvdbvdoketzlpdhkirmttkgvmqwjfqcqikbnyzvlsuxpnvptcbkjoggygghbvkmbaebikvly" + "lavudzccjyunjnqazihlpeecbxeiimimmjjewztrmggfrhsbvxnvqhjbyhtgfftkyyhiajqtkjmlurbl" + "aiuxppzfzumynhridmymfeaonqyrnrqdachqhsixnnfhsfmfkosolwoarhkmhbmxrfwicojiqrvzllbo" + "vlkdlsurbczlcvfddcnxiccstfqyudnfjwhdpdvwpguowkjvpwbecsjtuxdbtevwpkbdoutwatjoblgs" + "csfapnxdxaxyanuwvuddoqgilxdcznpmdykiskewnbqdsvrnmpbngzvrhkgglfyhqtypoejtqiqcuwjq" + "kbiuwxnjtwvegqhoneeewxdbwqqdipyzvfqmslutyuqfebtwdfoboobxruzspspguysayinklowkfggl" + "yosgqorbuuozjfkqzehptptdbfknkfdmaphktpuzwgjcluxiigpytlejqajvosrpfqvokpaurhzqxydb" + "aphihujakxkgpkktvsywqbeqqnvqfpkokpduowffpqeddgaeesuvrehtttezbrmqmsheeduzztooeleu" + "tvbazyjscveflomwwwkfcxzbzuuxxymgtnczxqhmfmvpactzcovibwizgjpzkxbghbyvraqjjozcwufu" + "bvzcsewyschjxucgkcftobwyrkkervodvvpeabzxbkfyobqmhrycezkrtyqbyddfazuezibxsajclayh" + "yoatnljujvftuedcygqzyfchbenwoffrfkhdhnchecuwkljmuwmjqfxmskimzhrztpagllrosusaofjm" + "kvqzljjlminstxbxydteofdhsjrvpxmjrfpwtevvcxiuabkthrqltmgvpmomklfpknorfxmcvmmmvumo" + "duwboexdejvlwjtpslwnhobenhyzlvyvkclmbqpdgjvflqfzdyshwhtqlsojdlgnazymlutdlzgxdomo" + "bqmcqcvojgmqlyiokaxrorxcswvngwmhsruhshzqlaybhjbctzizftuzbaljjxsjyxmzstvmyinbszsq" + "fylacpgmclczrxlgenrxatrkdgcnytjtxgrtqopssjjzrcsafpacrvtvscthxrpmsdrmenvaaetklhez" + "oqbfhweopoxvadkxqvbhiipegtasxonteityfibkpnuigancwisyowxeihfjuadsfjoxlewpnifjjceg" + "zitjxqpxcousmucwisdmvtinsuuwpzwuuawpcxzscpnqafftsadxcwtrragewwjlnavplniaeathgovt" + "usbgytesbncqtdazvhhjyvdbobuaqdeukualscrywgcqnsrwxupqymypjtgkxlezymjerjjwkrgrnmmy" + "lsxlwsdglcouajefvwfhjylykjgeojbnuirxdgtjsissxhdedndtfuruyxalrricqnkqpupskajjyltj" + "ezgzpdtlktykbvrierzvvzskehmvzgzieizwxhggddfanpnxbyjrekojhdorkzwkplgyumlqmyveesor" + "othsffgsuxdsealasqkycajhgdwgvjqyqlxfsghaaarruxplabewjpxkqwmckbaipcxhebrukmgpeaug" + "uuxicchlzzhhcrctuulypiwtcpsmmhhrllbrcuztikkewrumznhujmgibzzpnxiycmedaawqomhrsika" + "wqzyvdtqcjrzuhapyruccjotrkrlvyrgkrjglomqzxxjmev"; - fn qsort { - ([]) { [] } - (pivot @ rest) { - let - lesser = filter(fn (a, b) { a >= b }(pivot), rest); - greater = filter(fn (a, b) { a < b }(pivot), rest); - in - qsort(lesser) @@ [pivot] @@ qsort(greater) - } + // ~3.6 times faster than simple qsort + fn qqsort(lst) { + let + fn full_sort { + ([]) { [] } + (first @ rest) { + partition(first, rest, fn (lesser, greater) { + partial_sort(lesser, first @ full_sort(greater)) + }) + } + } + fn partial_sort { + (first @ rest, already_sorted) { + partition(first, rest, fn (lesser, greater) { + partial_sort(lesser, first @ partial_sort(greater, already_sorted)) + }) + } + ([], already_sorted) { already_sorted } + } + fn partition(key, lst, kont) { + let fn helper { + ([], lesser, greater) { kont(lesser, greater) } + (first @ rest, lesser, greater) { + if (key < first) { + helper(rest, lesser, first @ greater) + } else { + helper(rest, first @ lesser, greater) + } + } + } + in helper(lst, [], []) + } + in + full_sort(lst) } - fn filter { - (f, []) { [] } - (f, h @ t) { - if (f(h)) { - h @ filter(f, t) - } else { - filter(f, t) + fn qsort(lst) { + let + fn sort { + ([]) { [] } + (pivot @ rest) { + let + lesser = filter(fn (a, b) { a >= b }(pivot), rest); + greater = filter(fn (a, b) { a < b }(pivot), rest); + in + sort(lesser) @@ [pivot] @@ sort(greater) + } + } + + fn filter { + (f, []) { [] } + (f, h @ t) { + if (f(h)) { + h @ filter(f, t) + } else { + filter(f, t) + } + } } - } + in + sort(lst) } in - qsort(unsorted) + qqsort(unsorted) diff --git a/src/step.c b/src/step.c index f4b7ef9..91f9d39 100644 --- a/src/step.c +++ b/src/step.c @@ -785,7 +785,7 @@ static void step() { break; case BYTECODE_MATCH:{ // pop the dispach code, verify it's an integer and in range, and dispatch - int size = readCurrentByte(); + int size __attribute__((unused)) = readCurrentByte(); #ifdef DEBUG_STEP printf("MATCH [%d]", size); int save = state.C; From b87b077c3ab0d127a22bc561facee49d5a23cbc5 Mon Sep 17 00:00:00 2001 From: Bill Hails Date: Sun, 10 Mar 2024 12:14:41 +0000 Subject: [PATCH 18/33] working listutils, changed indent --- .indent.pro | 2 +- Makefile | 8 +- fn/listutils.fn | 267 +++++++++++++++++++++++++------------- src/anf_helper.h | 4 +- src/anf_normalize.c | 12 +- src/anf_normalize.h | 6 +- src/anf_pp.h | 10 +- src/annotate.c | 2 +- src/annotate.h | 12 +- src/ast_helper.h | 8 +- src/bigint.c | 4 +- src/bigint.h | 42 +++--- src/bytecode.c | 4 +- src/bytecode.h | 6 +- src/cekf.h | 16 +-- src/common.h | 16 ++- src/debug.h | 10 +- src/debugging_off.h | 20 +-- src/debugging_on.h | 22 ++-- src/desugaring.c | 6 +- src/desugaring.h | 4 +- src/hash.c | 8 +- src/hash.h | 12 +- src/lambda_conversion.c | 4 +- src/lambda_conversion.h | 6 +- src/lambda_helper.h | 10 +- src/lambda_pp.h | 4 +- src/lambda_substitution.c | 4 +- src/lambda_substitution.h | 8 +- src/memory.h | 50 +++---- src/module.h | 8 +- src/print_compiler.c | 4 +- src/print_compiler.h | 8 +- src/print_generator.c | 4 +- src/print_generator.h | 8 +- src/stack.c | 6 +- src/step.c | 8 +- src/step.h | 6 +- src/symbol.h | 4 +- src/symbols.h | 4 +- src/tc_analyze.c | 6 +- src/tc_analyze.h | 6 +- src/tc_helper.h | 6 +- src/tpmc_compare.h | 6 +- src/tpmc_helper.h | 10 +- src/tpmc_logic.c | 4 +- src/tpmc_logic.h | 6 +- src/tpmc_match.c | 8 +- src/tpmc_match.h | 4 +- src/tpmc_translate.c | 6 +- src/tpmc_translate.h | 6 +- src/value.h | 20 +-- 52 files changed, 410 insertions(+), 325 deletions(-) diff --git a/.indent.pro b/.indent.pro index 089edb1..36aab03 100644 --- a/.indent.pro +++ b/.indent.pro @@ -13,7 +13,7 @@ --no-space-after-function-call-names --no-tabs --pointer-align-right ---preprocessor-indentation4 +--preprocessor-indentation2 --space-after-for --space-after-if --space-after-while diff --git a/Makefile b/Makefile index 87f7637..5b9fe34 100644 --- a/Makefile +++ b/Makefile @@ -5,11 +5,11 @@ TARGET=cekf # in Ubuntu 22.10 # `ulimit -c unlimited` to turn on core dumps # written to /var/lib/apport/coredump/ -PROFILING=-pg -OPTIMIZING=-O2 -DEBUGGING=-g +MODE_P=-pg +MODE_O=-O2 +MODE_D=-g -DDEBUG_ANY -CCMODE = $(DEBUGGING) +CCMODE = $(MODE_D) CC=cc -Wall -Wextra -Werror $(CCMODE) LAXCC=cc -Werror $(CCMODE) diff --git a/fn/listutils.fn b/fn/listutils.fn index 2698da3..279dd47 100644 --- a/fn/listutils.fn +++ b/fn/listutils.fn @@ -1,100 +1,183 @@ -fn member { - (_, []) { false } - (x, x @ _) { true } - (x, _ @ t) { member(x, t) } -} - -fn map { - (_, []) { [] } - (func, h @ t) { func(h) @ map(func, t)) } -} - -fn length { - ([]) { 0 } - (_ @ t) { 1 + length(t) } -} - -fn foldl { - (_, [], acc) { acc } - (func, h @ t, acc) { foldl(func, t, func(h, acc)) } -} - -fn foldr(func, lst, acc) { - foldl(func, reverse(lst), acc) -} - -fn reverse (lst) { - foldl(fn (elem, acc) { elem @ acc }, lst, []) -} - -fn filter { - (_, []) { [] } - (func, h @ t) { - if (func(h)) { - h @ filter(func, t) - } else { - filter(func, t) +let + fn member { + (_, []) { false } + (x, x @ _) { true } + (x, _ @ t) { member(x, t) } + } + + fn map { + (_, []) { [] } + (func, h @ t) { func(h) @ map(func, t) } + } + + fn length { + ([]) { 0 } + (_ @ t) { 1 + length(t) } + } + + fn foldl { + (_, acc, []) { acc } + (func, acc, h @ t) { foldl(func, func(h, acc), t) } + } + + fn foldr(func, acc, lst) { + foldl(func, acc, reverse(lst)) + } + + fn foldl1(func, h @ t) { + foldl(func, h, t) + } + + fn foldr1(func, lst) { + foldl1(func, reverse(lst)) + } + + // reverse = foldl((@), []) + fn reverse (lst) { + foldl(fn (elem, acc) { elem @ acc }, [], lst) + } + + fn scanl (func, acc, lst) { + let fn scan { + (accl, []) { accl } + (acc = acch @ acct, lsth @ lstt) { scan(func(lsth, acch) @ acc, lstt) } } + in scan([acc], lst) } -} - -fn fill { - (0, _) { [] } - (n, v) { v @ fill(n - 1, v) } -} - -fn nth { - (0, h @ _) { h } - (n, _ @ t) { nth(n - 1, t) } -} - -fn sum(lst) { - foldl(fn (elm, acc) { elm + acc }, lst, 0) -} - -fn range(low, high) { - if (low >= high) { [] } - else { low @ range(low + 1, high) } -} - -fn dedup { - ([]) { [] } - (h @ t) { - h @ dedup(filter(t, fn(i) { h != i })) - } -} - -fn sort(lst) { - let - fn full_sort { - ([]) { [] } - (first @ rest) { - partition(first, rest, fn (lesser, greater) { - partial_sort(lesser, first @ full_sort(greater)) - }) + + fn filter { + (_, []) { [] } + (func, h @ t) { + if (func(h)) { + h @ filter(func, t) + } else { + filter(func, t) } } - fn partial_sort { - (first @ rest, already_sorted) { - partition(first, rest, fn (lesser, greater) { - partial_sort(lesser, first @ partial_sort(greater, already_sorted)) - }) - } - ([], sorted) { sorted } + } + + // BUG concat list of strings prints as a list of char rather than a string + fn concat(lst) { + foldr(fn (elem, acc) { elem @@ acc }, [], lst) + } + + fn any { + (_, []) { false } + (f, h @ t) { f(h) or any(f, t) } + } + + fn none(f, l) { + not any(f, l) + } + + fn all { + (_, []) { true } + (f, h @ t) { f(h) and all(f, t) } + } + + fn repeat { + (0, _) { [] } + (n, v) { v @ repeat(n - 1, v) } + } + + fn nth { + (0, h @ _) { h } + (n, _ @ t) { nth(n - 1, t) } + } + + // sum = foldl((+), 0) + fn sum(lst) { + foldl(fn (elm, acc) { elm + acc }, 0, lst) + } + + // product = foldl((*), 1) + fn product(lst) { + foldl(fn (elm, acc) { elm * acc }, 1, lst) + } + + fn zip { + (h1 @ t1, h2 @ t2) { [h1, h2] @ zip(t1, t2) } + (_, _) { [] } + } + + // BUG replacing (a @ []) with ([a]) causes error + fn last { + (a @ []) { a } + (_ @ t) { last(t) } + } + + fn empty { + ([]) { true } + (_) { false } + } + + fn take { + (0, _) { [] } + (n, []) { [] } + (n, h @ t) { h @ take(n - 1, t) } + } + + fn drop { + (0, l) { l } + (n, []) { [] } + (n, _ @ t) { drop(n - 1, t) } + } + + fn minimum(lst) { + foldl1(fn (elem, acc) { if (elem < acc) { elem } else { acc } }, lst) + } + + fn maximum(lst) { + foldl1(fn (elem, acc) { if (elem > acc) { elem } else { acc } }, lst) + } + + fn range(low, high) { + if (low >= high) { [] } + else { low @ range(low + 1, high) } + } + + fn dedup { + ([]) { [] } + (h @ t) { + h @ dedup(filter(fn(i) { h != i }, t)) } - fn partition(key, lst, kont) { - let fn helper { - ([], lesser, greater) { kont(lesser, greater) } - (first @ rest, lesser, greater) { - if (key < first) { - helper(rest, lesser, first @ greater) - } else { - helper(rest, first @ lesser, greater) + } + + fn sort(lst) { + let + fn full_sort { + ([]) { [] } + (first @ rest) { + partition(first, rest, fn (lesser, greater) { + partial_sort(lesser, first @ full_sort(greater)) + }) + } + } + fn partial_sort { + (first @ rest, already_sorted) { + partition(first, rest, fn (lesser, greater) { + partial_sort(lesser, first @ partial_sort(greater, already_sorted)) + }) + } + ([], sorted) { sorted } + } + fn partition(key, lst, kont) { + let fn helper { + ([], lesser, greater) { kont(lesser, greater) } + (first @ rest, lesser, greater) { + if (key < first) { + helper(rest, lesser, first @ greater) + } else { + helper(rest, first @ lesser, greater) + } } } + in helper(lst, [], []) } - in helper(lst, [], []) - } - in - full_sort(lst) -} + in + full_sort(lst) + } + +in + print(sort(dedup("the quick brown fox jumps over the lazy dog"))); + puts("\n") diff --git a/src/anf_helper.h b/src/anf_helper.h index ee3cf71..15073f8 100644 --- a/src/anf_helper.h +++ b/src/anf_helper.h @@ -1,5 +1,5 @@ #ifndef cekf_anf_helper_h -# define cekf_anf_helper_h +# define cekf_anf_helper_h /* * CEKF - VM supporting amb * Copyright (C) 2022-2023 Bill Hails @@ -22,6 +22,6 @@ * Generated from src/anf.yaml by tools/makeAST.py */ -# include "anf.h" +# include "anf.h" #endif diff --git a/src/anf_normalize.c b/src/anf_normalize.c index c115eb0..19abd60 100644 --- a/src/anf_normalize.c +++ b/src/anf_normalize.c @@ -25,13 +25,13 @@ #include "bigint.h" #ifdef DEBUG_ANF -# include -# include -# include "debug.h" -# include "lambda_pp.h" -# include "debugging_on.h" +# include +# include +# include "debug.h" +# include "lambda_pp.h" +# include "debugging_on.h" #else -# include "debugging_off.h" +# include "debugging_off.h" #endif static Exp *normalize(LamExp *lamExp, Exp *tail); diff --git a/src/anf_normalize.h b/src/anf_normalize.h index cc47b8e..8fa2f63 100644 --- a/src/anf_normalize.h +++ b/src/anf_normalize.h @@ -1,5 +1,5 @@ #ifndef cekf_anf_normalize_h -# define cekf_anf_normalize_h +# define cekf_anf_normalize_h /* * CEKF - VM supporting amb * Copyright (C) 2022-2023 Bill Hails @@ -18,8 +18,8 @@ * along with this program. If not, see . */ -# include "lambda.h" -# include "anf.h" +# include "lambda.h" +# include "anf.h" Exp *anfNormalize(LamExp *exp); diff --git a/src/anf_pp.h b/src/anf_pp.h index fd372f0..bb7296a 100644 --- a/src/anf_pp.h +++ b/src/anf_pp.h @@ -1,5 +1,5 @@ #ifndef cekf_anf_pp_h -# define cekf_anf_pp_h +# define cekf_anf_pp_h /* * CEKF - VM supporting amb * Copyright (C) 2022-2023 Bill Hails @@ -20,11 +20,11 @@ // Bespoke pretty-printer for anf -# include -# include +# include +# include -# include "common.h" -# include "anf.h" +# include "common.h" +# include "anf.h" void ppAexpLam(AexpLam *x); void ppAexpVarList(AexpVarList *x); diff --git a/src/annotate.c b/src/annotate.c index cb03c32..70d3dfe 100644 --- a/src/annotate.c +++ b/src/annotate.c @@ -27,7 +27,7 @@ #include "anf.h" #ifdef DEBUG_ANNOTATE -# include "debug.h" +# include "debug.h" #endif static bool locate(HashSymbol *var, CTEnv *env, int *frame, int *offset); diff --git a/src/annotate.h b/src/annotate.h index 51b69e9..78482b7 100644 --- a/src/annotate.h +++ b/src/annotate.h @@ -1,5 +1,5 @@ #ifndef cekf_annotate_h -# define cekf_annotate_h +# define cekf_annotate_h /* * CEKF - VM supporting amb * Copyright (C) 2022-2023 Bill Hails @@ -18,12 +18,12 @@ * along with this program. If not, see . */ -# include +# include -# include "common.h" -# include "anf.h" -# include "hash.h" -# include "memory.h" +# include "common.h" +# include "anf.h" +# include "hash.h" +# include "memory.h" void annotateExp(Exp *x, CTEnv *env); diff --git a/src/ast_helper.h b/src/ast_helper.h index 9b201eb..2267f90 100644 --- a/src/ast_helper.h +++ b/src/ast_helper.h @@ -1,5 +1,5 @@ #ifndef cekf_ast_helper_h -# define cekf_ast_helper_h +# define cekf_ast_helper_h /* * CEKF - VM supporting amb * Copyright (C) 2022-2023 Bill Hails @@ -18,9 +18,9 @@ * along with this program. If not, see . */ -# include "ast.h" -# include "hash.h" -# include "memory.h" +# include "ast.h" +# include "hash.h" +# include "memory.h" void markAstSymbolTable(void); diff --git a/src/bigint.c b/src/bigint.c index b9b1fed..db19d9b 100644 --- a/src/bigint.c +++ b/src/bigint.c @@ -7,9 +7,9 @@ #include #include #ifdef DEBUG_BIGINT -# include "debugging_on.h" +# include "debugging_on.h" #else -# include "debugging_off.h" +# include "debugging_off.h" #endif #define BIGINT_ASSERT(a, op, b) assert((a) op (b)); diff --git a/src/bigint.h b/src/bigint.h index 32c8ca1..e36483a 100644 --- a/src/bigint.h +++ b/src/bigint.h @@ -1,35 +1,35 @@ #ifndef BIGINT_H_INCLUDED -# define BIGINT_H_INCLUDED +# define BIGINT_H_INCLUDED -# ifdef __cplusplus +# ifdef __cplusplus extern "C" { -# endif +# endif -# include -# include -# include -# include -# include "memory.h" +# include +# include +# include +# include +# include "memory.h" /* any unsigned integer type */ typedef uint32_t bigint_word; -# define BIGINT_KARATSUBA_WORD_THRESHOLD 20 +# define BIGINT_KARATSUBA_WORD_THRESHOLD 20 -# define BIGINT_WORD_BITS ((sizeof(bigint_word) * CHAR_BIT)) -# define BIGINT_WORD_MAX ((bigint_word)-1) -# define BIGINT_HALF_WORD_MAX (BIGINT_WORD_MAX >> BIGINT_WORD_BITS / 2) +# define BIGINT_WORD_BITS ((sizeof(bigint_word) * CHAR_BIT)) +# define BIGINT_WORD_MAX ((bigint_word)-1) +# define BIGINT_HALF_WORD_MAX (BIGINT_WORD_MAX >> BIGINT_WORD_BITS / 2) -# define BIGINT_WORD_LO(a) ((a) & BIGINT_HALF_WORD_MAX) -# define BIGINT_WORD_HI(a) ((a) >> sizeof(a) * CHAR_BIT / 2) +# define BIGINT_WORD_LO(a) ((a) & BIGINT_HALF_WORD_MAX) +# define BIGINT_WORD_HI(a) ((a) >> sizeof(a) * CHAR_BIT / 2) -# define BIGINT_MIN(a, b) ((a) < (b) ? (a) : (b)) -# define BIGINT_MAX(a, b) ((a) > (b) ? (a) : (b)) -# define BIGINT_INT_ABS(a) ((a) < 0 ? -(unsigned int)(a) : (unsigned int)(a)) +# define BIGINT_MIN(a, b) ((a) < (b) ? (a) : (b)) +# define BIGINT_MAX(a, b) ((a) > (b) ? (a) : (b)) +# define BIGINT_INT_ABS(a) ((a) < 0 ? -(unsigned int)(a) : (unsigned int)(a)) -# define BIGINT_SWAP(type, a, b) do { type _tmp = a; a = b; b = _tmp; } while (0) +# define BIGINT_SWAP(type, a, b) do { type _tmp = a; a = b; b = _tmp; } while (0) -# define BIGINT_REVERSE(type, data, n) do {\ +# define BIGINT_REVERSE(type, data, n) do {\ int _i;\ for (_i = 0; _i < (n)/2; _i++) BIGINT_SWAP(type, data[_i], data[n - 1 - _i]);\ } while (0) @@ -178,7 +178,7 @@ extern "C" { double bigint_double(const bigint * src); -# ifdef __cplusplus +# ifdef __cplusplus } -# endif +# endif #endif diff --git a/src/bytecode.c b/src/bytecode.c index 363e8be..f50aacd 100644 --- a/src/bytecode.c +++ b/src/bytecode.c @@ -28,9 +28,9 @@ #include "common.h" #ifdef DEBUG_BYTECODE -# include "debugging_on.h" +# include "debugging_on.h" #else -# include "debugging_off.h" +# include "debugging_off.h" #endif void initByteCodeArray(ByteCodeArray *b) { diff --git a/src/bytecode.h b/src/bytecode.h index fed7519..8cf42c9 100644 --- a/src/bytecode.h +++ b/src/bytecode.h @@ -1,5 +1,5 @@ #ifndef cekf_bytecode_h -# define cekf_bytecode_h +# define cekf_bytecode_h /* * CEKF - VM supporting amb * Copyright (C) 2022-2023 Bill Hails @@ -18,8 +18,8 @@ * along with this program. If not, see . */ -# include "anf.h" -# include "memory.h" +# include "anf.h" +# include "memory.h" typedef uint8_t byte; typedef uint16_t word; diff --git a/src/cekf.h b/src/cekf.h index e67b1c4..eaa242f 100644 --- a/src/cekf.h +++ b/src/cekf.h @@ -1,5 +1,5 @@ #ifndef cekf_cekf_h -# define cekf_cekf_h +# define cekf_cekf_h /* * CEKF - VM supporting amb * Copyright (C) 2022-2023 Bill Hails @@ -22,14 +22,14 @@ * The structures of the CEKF machine. */ -# include -# include +# include +# include -# include "bytecode.h" -# include "common.h" -# include "anf.h" -# include "memory.h" -# include "value.h" +# include "bytecode.h" +# include "common.h" +# include "anf.h" +# include "memory.h" +# include "value.h" typedef size_t Control; diff --git a/src/common.h b/src/common.h index 281706a..5726caf 100644 --- a/src/common.h +++ b/src/common.h @@ -1,5 +1,5 @@ #ifndef cekf_common_h -# define cekf_common_h +# define cekf_common_h /* * CEKF - VM supporting amb * Copyright (C) 2022-2023 Bill Hails @@ -18,11 +18,12 @@ * along with this program. If not, see . */ -# include -# include +# include +# include typedef uint32_t hash_t; +# ifdef DEBUG_ANY // #define DEBUG_STACK // #define DEBUG_STEP // if DEBUG_STEP is defined, this sleeps for 1 second between each machine step @@ -53,10 +54,11 @@ typedef uint32_t hash_t; // #define DEBUG_PRINT_COMPILER // define this to turn on additional safety checks for things that shouldn't but just possibly might happen # define SAFETY_CHECKS +# endif -# ifndef __GNUC__ -# define __attribute__(x) -# endif +# ifndef __GNUC__ +# define __attribute__(x) +# endif void cant_happen(const char *message, ...) __attribute__((noreturn, format(printf, 1, 2))); void can_happen(const char *message, ...) @@ -64,6 +66,6 @@ void can_happen(const char *message, ...) void eprintf(const char *message, ...) __attribute__((format(printf, 1, 2))); bool hadErrors(void); -# define PAD_WIDTH 2 +# define PAD_WIDTH 2 #endif diff --git a/src/debug.h b/src/debug.h index 6974b63..c632cef 100644 --- a/src/debug.h +++ b/src/debug.h @@ -1,5 +1,5 @@ #ifndef cekf_debug_h -# define cekf_debug_h +# define cekf_debug_h /* * CEKF - VM supporting amb * Copyright (C) 2022-2023 Bill Hails @@ -18,10 +18,10 @@ * along with this program. If not, see . */ -# include "cekf.h" -# include "anf.h" -# include "annotate.h" -# include "bytecode.h" +# include "cekf.h" +# include "anf.h" +# include "annotate.h" +# include "bytecode.h" void printCEKF(CEKF * x); diff --git a/src/debugging_off.h b/src/debugging_off.h index 2827144..f94bc08 100644 --- a/src/debugging_off.h +++ b/src/debugging_off.h @@ -1,5 +1,5 @@ #ifndef cekf_debugging -# define cekf_debugging +# define cekf_debugging /* * CEKF - VM supporting amb * Copyright (C) 2022-2023 Bill Hails @@ -20,14 +20,14 @@ * Term Pattern Matching Compiler stage 4. code generation */ -# define ENTER(n) -# define LEAVE(n) -# define DEBUG(...) -# define DEBUGN(...) -# define IFDEBUG(x) -# define IFDEBUGN(x) -# define NEWLINE() -# define DEBUGGING_ON() -# define DEBUGGING_OFF() +# define ENTER(n) +# define LEAVE(n) +# define DEBUG(...) +# define DEBUGN(...) +# define IFDEBUG(x) +# define IFDEBUGN(x) +# define NEWLINE() +# define DEBUGGING_ON() +# define DEBUGGING_OFF() #endif diff --git a/src/debugging_on.h b/src/debugging_on.h index d4abe09..e37bf40 100644 --- a/src/debugging_on.h +++ b/src/debugging_on.h @@ -1,5 +1,5 @@ #ifndef cekf_debugging -# define cekf_debugging +# define cekf_debugging /* * CEKF - VM supporting amb * Copyright (C) 2022-2023 Bill Hails @@ -22,9 +22,9 @@ static int _debugInvocationId __attribute__((unused)) = 0; static bool _debuggingOn __attribute__((unused)) = true; static int _debuggingDepth __attribute__((unused)) = 0; -# define __DEBUGPAD__() do { for (int pads = _debuggingDepth / 4; pads > 0; pads--) { eprintf(" |"); } eprintf("%*s", _debuggingDepth % 4, ""); } while (false) +# define __DEBUGPAD__() do { for (int pads = _debuggingDepth / 4; pads > 0; pads--) { eprintf(" |"); } eprintf("%*s", _debuggingDepth % 4, ""); } while (false) -# define DEBUG(...) do { \ +# define DEBUG(...) do { \ if (_debuggingOn) { \ eprintf("%s:%-5d", __FILE__, __LINE__); \ __DEBUGPAD__(); \ @@ -33,7 +33,7 @@ static int _debuggingDepth __attribute__((unused)) = 0; } \ } while(0) -# define DEBUGN(...) do { \ +# define DEBUGN(...) do { \ if (_debuggingOn) { \ eprintf("%s:%-5d", __FILE__, __LINE__); \ __DEBUGPAD__(); \ @@ -41,18 +41,18 @@ static int _debuggingDepth __attribute__((unused)) = 0; } \ } while(0) -# define ENTER(name) int _debugMyId = _debugInvocationId++; DEBUG("ENTER " #name " #%d", _debugMyId); _debuggingDepth++ +# define ENTER(name) int _debugMyId = _debugInvocationId++; DEBUG("ENTER " #name " #%d", _debugMyId); _debuggingDepth++ -# define LEAVE(name) _debuggingDepth--; DEBUG("LEAVE " #name " #%d", _debugMyId) +# define LEAVE(name) _debuggingDepth--; DEBUG("LEAVE " #name " #%d", _debugMyId) -# define NEWLINE() do { if (_debuggingOn) eprintf("\n"); } while(0) +# define NEWLINE() do { if (_debuggingOn) eprintf("\n"); } while(0) -# define IFDEBUG(x) do { if (_debuggingOn) { eprintf("%s:%-5d", __FILE__, __LINE__); __DEBUGPAD__(); x; NEWLINE(); } } while(0) +# define IFDEBUG(x) do { if (_debuggingOn) { eprintf("%s:%-5d", __FILE__, __LINE__); __DEBUGPAD__(); x; NEWLINE(); } } while(0) -# define IFDEBUGN(x) do { if (_debuggingOn) { x; NEWLINE(); } } while(0) +# define IFDEBUGN(x) do { if (_debuggingOn) { x; NEWLINE(); } } while(0) -# define DEBUGGING_ON() do { _debuggingOn = true; } while (0) +# define DEBUGGING_ON() do { _debuggingOn = true; } while (0) -# define DEBUGGING_OFF() do { _debuggingOn = false; } while (0) +# define DEBUGGING_OFF() do { _debuggingOn = false; } while (0) #endif diff --git a/src/desugaring.c b/src/desugaring.c index e0a8b12..2a310e8 100644 --- a/src/desugaring.c +++ b/src/desugaring.c @@ -26,7 +26,7 @@ #include "symbol.h" #ifdef DEBUG_DESUGARING -# include "debug.h" +# include "debug.h" #endif static AexpLam *desugarAexpLam(AexpLam *x); @@ -45,9 +45,9 @@ static Aexp *desugarAexp(Aexp *x); static Cexp *desugarCexp(Cexp *x); #ifdef DEBUG_DESUGARING -# define DEBUG_DESUGAR(type, val) do { printf("desugar" #type ": "); print ## type (val); printf("\n"); } while(0) +# define DEBUG_DESUGAR(type, val) do { printf("desugar" #type ": "); print ## type (val); printf("\n"); } while(0) #else -# define DEBUG_DESUGAR(type, val) do {} while(0) +# define DEBUG_DESUGAR(type, val) do {} while(0) #endif static AexpLam *desugarAexpLam(AexpLam *x) { diff --git a/src/desugaring.h b/src/desugaring.h index 99ad368..afaf6c7 100644 --- a/src/desugaring.h +++ b/src/desugaring.h @@ -1,5 +1,5 @@ #ifndef cekf_desugaring_h -# define cekf_desugaring_h +# define cekf_desugaring_h /* * CEKF - VM supporting amb * Copyright (C) 2022-2023 Bill Hails @@ -18,7 +18,7 @@ * along with this program. If not, see . */ -# include "anf.h" +# include "anf.h" Exp *desugarExp(Exp *expr); diff --git a/src/hash.c b/src/hash.c index d078024..6aea652 100644 --- a/src/hash.c +++ b/src/hash.c @@ -27,9 +27,9 @@ #include "hash.h" #include "memory.h" #ifdef DEBUG_HASHTABLE -# include "debugging_on.h" +# include "debugging_on.h" #else -# include "debugging_off.h" +# include "debugging_off.h" #endif bool quietPrintHashTable = false; @@ -166,10 +166,10 @@ void hashSet(HashTable *table, HashSymbol *var, void *src) { void *target = valuePtr(table, index); #if defined(DEBUG_HASHTABLE) || defined(DEBUG_LEAK) eprintf("memcpy(%p, %p, %ld);\n", target, src, table->valuesize); -# ifdef DEBUG_LEAK +# ifdef DEBUG_LEAK eprintf("// *%p == %p, table->values == %p\n", src, *((void **) src), table->values); -# endif +# endif #endif memcpy(target, src, table->valuesize); } diff --git a/src/hash.h b/src/hash.h index 29f8472..8b9c126 100644 --- a/src/hash.h +++ b/src/hash.h @@ -1,5 +1,5 @@ #ifndef cekf_hash_h -# define cekf_hash_h +# define cekf_hash_h /* * CEKF - VM supporting amb * Copyright (C) 2022-2023 Bill Hails @@ -18,13 +18,13 @@ * along with this program. If not, see . */ -# include +# include -# include "common.h" -# include "memory.h" -# include "value.h" +# include "common.h" +# include "memory.h" +# include "value.h" -# define HASH_MAX_LOAD 0.75 +# define HASH_MAX_LOAD 0.75 typedef struct HashSymbol { struct Header header; diff --git a/src/lambda_conversion.c b/src/lambda_conversion.c index 811eac0..5317b74 100644 --- a/src/lambda_conversion.c +++ b/src/lambda_conversion.c @@ -58,9 +58,9 @@ static LamTypeConstructorArgs *convertAstTypeList(AstTypeList *typeList); static HashSymbol *dollarSubstitute(HashSymbol *original); #ifdef DEBUG_LAMBDA_CONVERT -# include "debugging_on.h" +# include "debugging_on.h" #else -# include "debugging_off.h" +# include "debugging_off.h" #endif static bool inPreamble = true; // preamble is treated specially diff --git a/src/lambda_conversion.h b/src/lambda_conversion.h index 5805ac7..2eb2a29 100644 --- a/src/lambda_conversion.h +++ b/src/lambda_conversion.h @@ -1,5 +1,5 @@ #ifndef cekf_lambda_conversion_h -# define cekf_lambda_conversion_h +# define cekf_lambda_conversion_h /* * CEKF - VM supporting amb * Copyright (C) 2022-2023 Bill Hails @@ -18,8 +18,8 @@ * along with this program. If not, see . */ -# include "ast.h" -# include "lambda.h" +# include "ast.h" +# include "lambda.h" LamExp *lamConvertNest(AstNest *nest, LamContext *env); #endif diff --git a/src/lambda_helper.h b/src/lambda_helper.h index 701913e..b973134 100644 --- a/src/lambda_helper.h +++ b/src/lambda_helper.h @@ -1,5 +1,5 @@ #ifndef cekf_lambda_helper_h -# define cekf_lambda_helper_h +# define cekf_lambda_helper_h /* * CEKF - VM supporting amb * Copyright (C) 2022-2023 Bill Hails @@ -18,10 +18,10 @@ * along with this program. If not, see . */ -# include "lambda.h" -# include "lambda_debug.h" -# include "hash.h" -# include "memory.h" +# include "lambda.h" +# include "lambda_debug.h" +# include "hash.h" +# include "memory.h" void printLambdaSymbol(HashSymbol *x, int depth); LamContext *extendLamContext(LamContext *parent); diff --git a/src/lambda_pp.h b/src/lambda_pp.h index 6964008..cfb9b72 100644 --- a/src/lambda_pp.h +++ b/src/lambda_pp.h @@ -1,5 +1,5 @@ #ifndef cekf_lambda_pp_h -# define cekf_lambda_pp_h +# define cekf_lambda_pp_h /* * CEKF - VM supporting amb * Copyright (C) 2022-2023 Bill Hails @@ -21,7 +21,7 @@ * */ -# include "lambda.h" +# include "lambda.h" void ppLamExpD(LamExp *exp, int depth); void ppLamLam(LamLam *lam); diff --git a/src/lambda_substitution.c b/src/lambda_substitution.c index ae8e2fb..798adfb 100644 --- a/src/lambda_substitution.c +++ b/src/lambda_substitution.c @@ -29,9 +29,9 @@ #include "print_generator.h" #ifdef DEBUG_LAMBDA_SUBSTITUTE -# include "debugging_on.h" +# include "debugging_on.h" #else -# include "debugging_off.h" +# include "debugging_off.h" #endif static HashSymbol *performVarSubstitutions(HashSymbol *var, TpmcSubstitutionTable diff --git a/src/lambda_substitution.h b/src/lambda_substitution.h index b54ae79..5e65ede 100644 --- a/src/lambda_substitution.h +++ b/src/lambda_substitution.h @@ -1,5 +1,5 @@ #ifndef cekf_lambda_substitution_h -# define cekf_lambda_substitution_h +# define cekf_lambda_substitution_h /* * CEKF - VM supporting amb * Copyright (C) 2022-2023 Bill Hails @@ -18,9 +18,9 @@ * along with this program. If not, see . */ -# include "ast.h" -# include "tpmc.h" -# include "lambda.h" +# include "ast.h" +# include "tpmc.h" +# include "lambda.h" LamExp *lamPerformSubstitutions(LamExp *exp, TpmcSubstitutionTable *substitutions); diff --git a/src/memory.h b/src/memory.h index c444092..ebc5996 100644 --- a/src/memory.h +++ b/src/memory.h @@ -1,5 +1,5 @@ #ifndef cekf_memory_h -# define cekf_memory_h +# define cekf_memory_h /* * CEKF - VM supporting amb * Copyright (C) 2022-2023 Bill Hails @@ -18,16 +18,16 @@ * along with this program. If not, see . */ -# include -# include +# include +# include struct Header; -# include "ast_objtypes.h" -# include "anf_objtypes.h" -# include "lambda_objtypes.h" -# include "tpmc_objtypes.h" -# include "tc_objtypes.h" +# include "ast_objtypes.h" +# include "anf_objtypes.h" +# include "lambda_objtypes.h" +# include "tpmc_objtypes.h" +# include "tc_objtypes.h" typedef enum { @@ -85,29 +85,29 @@ void validateLastAlloc(void); void reportMemory(void); -# define EXIT_OOM 2 +# define EXIT_OOM 2 -# define NEW_VEC(size) ((Vec *)allocate(sizeof(Vec) + size * sizeof(Value), OBJTYPE_VEC)) -# define FREE_VEC(vec) ((void)reallocate(vec, sizeof(vec) + vec->size * sizeof(Value), 0)) +# define NEW_VEC(size) ((Vec *)allocate(sizeof(Vec) + size * sizeof(Value), OBJTYPE_VEC)) +# define FREE_VEC(vec) ((void)reallocate(vec, sizeof(vec) + vec->size * sizeof(Value), 0)) // Allocation for directly managed objects -# define NEW(thing, type) ((thing *)allocate(sizeof(thing), type)) -# define FREE(thing, type) ((void)reallocate(thing, sizeof(type), 0)) +# define NEW(thing, type) ((thing *)allocate(sizeof(thing), type)) +# define FREE(thing, type) ((void)reallocate(thing, sizeof(type), 0)) // Allocation for indirectly managed objects -# define ALLOCATE(type) ((type *)reallocate(NULL, 0, sizeof(type))) +# define ALLOCATE(type) ((type *)reallocate(NULL, 0, sizeof(type))) -# define NEW_ARRAY(type, count) ((type *)reallocate(NULL, 0, sizeof(type) * (count))) -# define FREE_ARRAY(type, array, count) ((void)reallocate(array, sizeof(type) * (count), 0)) -# define GROW_ARRAY(type, array, oldcount, newcount) ((type *)reallocate(array, sizeof(type) * (oldcount), sizeof(type) * (newcount))) -# define MOVE_ARRAY(type, dest, src, amount) (memmove((dest), (src), sizeof(type) * (amount))) -# define COPY_ARRAY(type, dest, src, amount) (memcpy((dest), (src), sizeof(type) * (amount))) +# define NEW_ARRAY(type, count) ((type *)reallocate(NULL, 0, sizeof(type) * (count))) +# define FREE_ARRAY(type, array, count) ((void)reallocate(array, sizeof(type) * (count), 0)) +# define GROW_ARRAY(type, array, oldcount, newcount) ((type *)reallocate(array, sizeof(type) * (oldcount), sizeof(type) * (newcount))) +# define MOVE_ARRAY(type, dest, src, amount) (memmove((dest), (src), sizeof(type) * (amount))) +# define COPY_ARRAY(type, dest, src, amount) (memcpy((dest), (src), sizeof(type) * (amount))) -# define STARTPROTECT() protect(NULL); -# define PROTECT(x) protect((Header *)(x)) -# define UNPROTECT(i) unProtect(i) -# define REPLACE_PROTECT(i, x) replaceProtect(i, (Header *)(x)) +# define STARTPROTECT() protect(NULL); +# define PROTECT(x) protect((Header *)(x)) +# define UNPROTECT(i) unProtect(i) +# define REPLACE_PROTECT(i, x) replaceProtect(i, (Header *)(x)) -# define MARK(obj) (((Header *)(obj))->keep = true) -# define MARKED(obj) (((Header *)(obj))->keep == true) +# define MARK(obj) (((Header *)(obj))->keep = true) +# define MARKED(obj) (((Header *)(obj))->keep == true) #endif diff --git a/src/module.h b/src/module.h index 778f07a..10b6d6d 100644 --- a/src/module.h +++ b/src/module.h @@ -1,9 +1,9 @@ #ifndef cekf_module_h -# define cekf_module_h +# define cekf_module_h -# include -# include "ast.h" -# include "memory.h" +# include +# include "ast.h" +# include "memory.h" typedef struct PmModule { Header header; diff --git a/src/print_compiler.c b/src/print_compiler.c index 95587f1..4677d25 100644 --- a/src/print_compiler.c +++ b/src/print_compiler.c @@ -31,9 +31,9 @@ #include "symbols.h" #ifdef DEBUG_PRINT_COMPILER -# include "debugging_on.h" +# include "debugging_on.h" #else -# include "debugging_off.h" +# include "debugging_off.h" #endif static LamExp *compilePrinterForFunction(TcFunction *function); diff --git a/src/print_compiler.h b/src/print_compiler.h index 1472bdd..b952829 100644 --- a/src/print_compiler.h +++ b/src/print_compiler.h @@ -1,5 +1,5 @@ #ifndef cekf_print_compiler_h -# define cekf_print_compiler_h +# define cekf_print_compiler_h /* * CEKF - VM supporting amb * Copyright (C) 2022-2023 Bill Hails @@ -18,9 +18,9 @@ * along with this program. If not, see . */ -# include "lambda.h" -# include "value.h" -# include "tc.h" +# include "lambda.h" +# include "value.h" +# include "tc.h" LamExp *compilePrinterForType(TcType *type, TcEnv *env); diff --git a/src/print_generator.c b/src/print_generator.c index 961217a..0b6f725 100644 --- a/src/print_generator.c +++ b/src/print_generator.c @@ -32,9 +32,9 @@ #include "symbols.h" #ifdef DEBUG_PRINT_GENERATOR -# include "debugging_on.h" +# include "debugging_on.h" #else -# include "debugging_off.h" +# include "debugging_off.h" #endif static LamLetRecBindings *makePrintFunction(LamTypeDef *typeDef, diff --git a/src/print_generator.h b/src/print_generator.h index 89dccc6..47f5bf4 100644 --- a/src/print_generator.h +++ b/src/print_generator.h @@ -1,5 +1,5 @@ #ifndef cekf_print_generator_h -# define cekf_print_generator_h +# define cekf_print_generator_h /* * CEKF - VM supporting amb * Copyright (C) 2022-2023 Bill Hails @@ -18,9 +18,9 @@ * along with this program. If not, see . */ -# include "lambda.h" -# include "value.h" -# include "tc.h" +# include "lambda.h" +# include "value.h" +# include "tc.h" LamLetRecBindings *makePrintFunctions(LamTypeDefList *typeDefs, LamLetRecBindings *rest, diff --git a/src/stack.c b/src/stack.c index 6e4ea01..60a42f1 100644 --- a/src/stack.c +++ b/src/stack.c @@ -27,10 +27,10 @@ #include #include #ifdef DEBUG_STACK -# include "debug.h" -# include "debugging_on.h" +# include "debug.h" +# include "debugging_on.h" #else -# include "debugging_off.h" +# include "debugging_off.h" #endif Snapshot noSnapshot = { diff --git a/src/step.c b/src/step.c index 91f9d39..e1637fe 100644 --- a/src/step.c +++ b/src/step.c @@ -32,9 +32,9 @@ #include "hash.h" #ifdef DEBUG_STEP -# define DEBUGPRINTF(...) printf(__VA_ARGS__) +# define DEBUGPRINTF(...) printf(__VA_ARGS__) #else -# define DEBUGPRINTF(...) +# define DEBUGPRINTF(...) #endif /** @@ -1047,9 +1047,9 @@ static void step() { cant_happen("unrecognised bytecode %d in step()", bytecode); } #ifdef DEBUG_STEP -# ifdef DEBUG_SLOW_STEP +# ifdef DEBUG_SLOW_STEP sleep(1); -# endif +# endif #endif } } diff --git a/src/step.h b/src/step.h index 6a01fba..4859063 100644 --- a/src/step.h +++ b/src/step.h @@ -1,5 +1,5 @@ #ifndef cekf_step_h -# define cekf_step_h +# define cekf_step_h /* * CEKF - VM supporting amb * Copyright (C) 2022-2023 Bill Hails @@ -18,8 +18,8 @@ * along with this program. If not, see . */ -# include "bytecode.h" -# include "value.h" +# include "bytecode.h" +# include "value.h" Value run(ByteCodeArray B); diff --git a/src/symbol.h b/src/symbol.h index d5e626e..ed31c11 100644 --- a/src/symbol.h +++ b/src/symbol.h @@ -1,5 +1,5 @@ #ifndef cekf_symbol_h -# define cekf_symbol_h +# define cekf_symbol_h /* * CEKF - VM supporting amb * Copyright (C) 2022-2023 Bill Hails @@ -18,7 +18,7 @@ * along with this program. If not, see . */ -# include "hash.h" +# include "hash.h" HashSymbol *genSym(char *prefix); diff --git a/src/symbols.h b/src/symbols.h index fff1489..c87bcfb 100644 --- a/src/symbols.h +++ b/src/symbols.h @@ -1,5 +1,5 @@ #ifndef cekf_symbols_h -# define cekf_symbols_h +# define cekf_symbols_h /* * CEKF - VM supporting amb * Copyright (C) 2022-2023 Bill Hails @@ -18,7 +18,7 @@ * along with this program. If not, see . */ -# include "symbol.h" +# include "symbol.h" HashSymbol *addSymbol(void); HashSymbol *andSymbol(void); diff --git a/src/tc_analyze.c b/src/tc_analyze.c index b622a6f..e84e814 100644 --- a/src/tc_analyze.c +++ b/src/tc_analyze.c @@ -29,10 +29,10 @@ #include "lambda_pp.h" #ifdef DEBUG_TC -# include "debugging_on.h" -# include "lambda_pp.h" +# include "debugging_on.h" +# include "lambda_pp.h" #else -# include "debugging_off.h" +# include "debugging_off.h" #endif static TcEnv *extendEnv(TcEnv *parent); diff --git a/src/tc_analyze.h b/src/tc_analyze.h index fd6c0c4..c96270f 100644 --- a/src/tc_analyze.h +++ b/src/tc_analyze.h @@ -1,5 +1,5 @@ #ifndef cekf_tc_analyze_h -# define cekf_tc_analyze_h +# define cekf_tc_analyze_h /* * CEKF - VM supporting amb * Copyright (C) 2022-2023 Bill Hails @@ -18,8 +18,8 @@ * along with this program. If not, see . */ -# include "tc.h" -# include "lambda.h" +# include "tc.h" +# include "lambda.h" TcEnv *tc_init(void); TcType *tc_analyze(LamExp *exp, TcEnv *env); diff --git a/src/tc_helper.h b/src/tc_helper.h index 5fe5d32..586288c 100644 --- a/src/tc_helper.h +++ b/src/tc_helper.h @@ -1,5 +1,5 @@ #ifndef cekf_tc_helper_h -# define cekf_tc_helper_h +# define cekf_tc_helper_h /* * CEKF - VM supporting amb * Copyright (C) 2022-2023 Bill Hails @@ -18,8 +18,8 @@ * along with this program. If not, see . */ -# include "ast_helper.h" -# include "tc.h" +# include "ast_helper.h" +# include "tc.h" void ppTcType(TcType *type); void ppTcFunction(TcFunction *function); diff --git a/src/tpmc_compare.h b/src/tpmc_compare.h index 3f4b0b1..ab24f23 100644 --- a/src/tpmc_compare.h +++ b/src/tpmc_compare.h @@ -1,5 +1,5 @@ #ifndef cekf_tpmc_compare_h -# define cekf_tpmc_compare_h +# define cekf_tpmc_compare_h /* * CEKF - VM supporting amb * Copyright (C) 2022-2023 Bill Hails @@ -20,8 +20,8 @@ * Term Pattern Matching Compiler logic */ -# include -# include "tpmc.h" +# include +# include "tpmc.h" bool tpmcStateEq(TpmcState *a, TpmcState *b); bool tpmcStateValueEq(TpmcStateValue *a, TpmcStateValue *b); diff --git a/src/tpmc_helper.h b/src/tpmc_helper.h index bc7231f..579efbb 100644 --- a/src/tpmc_helper.h +++ b/src/tpmc_helper.h @@ -1,5 +1,5 @@ #ifndef cekf_tpmc_helper_h -# define cekf_tpmc_helper_h +# define cekf_tpmc_helper_h /* * CEKF - VM supporting amb * Copyright (C) 2022-2023 Bill Hails @@ -18,9 +18,9 @@ * along with this program. If not, see . */ -# include "ast_helper.h" -# include "tpmc.h" -# include "hash.h" -# include "memory.h" +# include "ast_helper.h" +# include "tpmc.h" +# include "hash.h" +# include "memory.h" #endif diff --git a/src/tpmc_logic.c b/src/tpmc_logic.c index 7d801da..f6785ce 100644 --- a/src/tpmc_logic.c +++ b/src/tpmc_logic.c @@ -31,9 +31,9 @@ #include "lambda_substitution.h" #include "lambda_pp.h" #ifdef DEBUG_TPMC_LOGIC -# include "debugging_on.h" +# include "debugging_on.h" #else -# include "debugging_off.h" +# include "debugging_off.h" #endif static TpmcPattern *convertPattern(AstArg *arg, LamContext *env); diff --git a/src/tpmc_logic.h b/src/tpmc_logic.h index 11caec5..e47f535 100644 --- a/src/tpmc_logic.h +++ b/src/tpmc_logic.h @@ -1,5 +1,5 @@ #ifndef cekf_tpmc_logic_h -# define cekf_tpmc_logic_h +# define cekf_tpmc_logic_h /* * CEKF - VM supporting amb * Copyright (C) 2022-2023 Bill Hails @@ -18,8 +18,8 @@ * along with this program. If not, see . */ -# include "ast.h" -# include "lambda.h" +# include "ast.h" +# include "lambda.h" LamLam *tpmcConvert(int nargs, int nbodies, AstArgList **argList, LamExp **actions, LamContext *env); diff --git a/src/tpmc_match.c b/src/tpmc_match.c index aee9039..f92eac3 100644 --- a/src/tpmc_match.c +++ b/src/tpmc_match.c @@ -29,9 +29,9 @@ #include "symbol.h" #ifdef DEBUG_TPMC_MATCH -# include "debugging_on.h" +# include "debugging_on.h" #else -# include "debugging_off.h" +# include "debugging_off.h" #endif TpmcState *tpmcMakeState(TpmcStateValue *val) { @@ -643,9 +643,9 @@ void ppPattern(TpmcPattern *pattern) { } } -# define PPPATTERN(p) ppPattern(p); eprintf("\n") +# define PPPATTERN(p) ppPattern(p); eprintf("\n") #else -# define PPPATTERN(p) +# define PPPATTERN(p) #endif static TpmcState *mixture(TpmcMatrix *matrix, TpmcStateArray *finalStates, diff --git a/src/tpmc_match.h b/src/tpmc_match.h index a0cb54b..1bc9fe5 100644 --- a/src/tpmc_match.h +++ b/src/tpmc_match.h @@ -1,5 +1,5 @@ #ifndef cekf_tpmc_match_h -# define cekf_tpmc_match_h +# define cekf_tpmc_match_h /* * CEKF - VM supporting amb * Copyright (C) 2022-2023 Bill Hails @@ -20,7 +20,7 @@ * Term Pattern Matching Compiler match algorithm */ -# include "tpmc.h" +# include "tpmc.h" TpmcState *tpmcMakeState(TpmcStateValue *val); TpmcState *tpmcMatch(TpmcMatrix *matrix, TpmcStateArray *states, diff --git a/src/tpmc_translate.c b/src/tpmc_translate.c index 9fe3680..9eccdae 100644 --- a/src/tpmc_translate.c +++ b/src/tpmc_translate.c @@ -27,10 +27,10 @@ #include "common.h" #ifdef DEBUG_TPMC_TRANSLATE -# include "debug_tpmc.h" -# include "debugging_on.h" +# include "debug_tpmc.h" +# include "debugging_on.h" #else -# include "debugging_off.h" +# include "debugging_off.h" #endif static LamExp *translateStateToInlineCode(TpmcState *dfa, diff --git a/src/tpmc_translate.h b/src/tpmc_translate.h index d9b9d09..8100b78 100644 --- a/src/tpmc_translate.h +++ b/src/tpmc_translate.h @@ -1,5 +1,5 @@ #ifndef cekf_tpmc_translate_h -# define cekf_tpmc_translate_h +# define cekf_tpmc_translate_h /* * CEKF - VM supporting amb * Copyright (C) 2022-2023 Bill Hails @@ -18,8 +18,8 @@ * along with this program. If not, see . */ -# include "tpmc.h" -# include "lambda.h" +# include "tpmc.h" +# include "lambda.h" LamExp *tpmcTranslate(TpmcState *dfa); #endif diff --git a/src/value.h b/src/value.h index fa927da..2802fe3 100644 --- a/src/value.h +++ b/src/value.h @@ -1,5 +1,5 @@ #ifndef cekf_value_h -# define cekf_value_h +# define cekf_value_h /* * CEKF - VM supporting amb * Copyright (C) 2022-2023 Bill Hails @@ -18,7 +18,7 @@ * along with this program. If not, see . */ -# include "bigint.h" +# include "bigint.h" typedef enum { VALUE_TYPE_VOID, @@ -46,15 +46,15 @@ typedef struct Value { ValueVal val; } Value; -# define VALUE_VAL_STDINT(x) ((ValueVal){.z = (x)}) -# define VALUE_VAL_BIGINT(x) ((ValueVal){.b = (x)}) -# define VALUE_VAL_CHARACTER(x) ((ValueVal){.c = (x)}) +# define VALUE_VAL_STDINT(x) ((ValueVal){.z = (x)}) +# define VALUE_VAL_BIGINT(x) ((ValueVal){.b = (x)}) +# define VALUE_VAL_CHARACTER(x) ((ValueVal){.c = (x)}) // CLO and PCLO share the same Clo struct -# define VALUE_VAL_CLO(x) ((ValueVal){.clo = (x)}) -# define VALUE_VAL_PCLO(x) ((ValueVal){.clo = (x)}) -# define VALUE_VAL_CONT(x) ((ValueVal){.k = (x)}) -# define VALUE_VAL_VEC(x) ((ValueVal){.vec = (x)}) -# define VALUE_VAL_NONE() ((ValueVal){.none = NULL}) +# define VALUE_VAL_CLO(x) ((ValueVal){.clo = (x)}) +# define VALUE_VAL_PCLO(x) ((ValueVal){.clo = (x)}) +# define VALUE_VAL_CONT(x) ((ValueVal){.k = (x)}) +# define VALUE_VAL_VEC(x) ((ValueVal){.vec = (x)}) +# define VALUE_VAL_NONE() ((ValueVal){.none = NULL}) // constants extern Value vTrue; From 87bad2a1f9d442ab58c0a39358eba3d406a7afbd Mon Sep 17 00:00:00 2001 From: Bill Hails Date: Sun, 10 Mar 2024 12:15:30 +0000 Subject: [PATCH 19/33] useful shell stuff --- utils.sh | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 utils.sh diff --git a/utils.sh b/utils.sh new file mode 100644 index 0000000..bbad0c5 --- /dev/null +++ b/utils.sh @@ -0,0 +1,3 @@ +fnd () { + grep -rwn $1 src +} From 1644df99623f1fe826da1df68ce4fbdaf74d7518 Mon Sep 17 00:00:00 2001 From: Bill Hails Date: Mon, 11 Mar 2024 17:06:14 +0000 Subject: [PATCH 20/33] listUtils.zipWith --- fn/listutils.fn | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fn/listutils.fn b/fn/listutils.fn index 279dd47..abad241 100644 --- a/fn/listutils.fn +++ b/fn/listutils.fn @@ -100,6 +100,11 @@ let (_, _) { [] } } + fn zipWith { + (f, h1 @ t1, h2 @ t2) { f(h1, h2) @ zipWith(f, t1, t2) } + (_, _, _) { [] } + } + // BUG replacing (a @ []) with ([a]) causes error fn last { (a @ []) { a } @@ -179,5 +184,5 @@ let } in - print(sort(dedup("the quick brown fox jumps over the lazy dog"))); + print(zipWith(fn (x, y) { x * y }, [1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12])); puts("\n") From e88167b355cbf34200301bbb14eedafea27012d0 Mon Sep 17 00:00:00 2001 From: Bill Hails Date: Sat, 16 Mar 2024 13:35:19 +0000 Subject: [PATCH 21/33] "fixed" issue with forward references in letrec --- fn/bugs.fn | 33 +++ fn/listutils.fn | 2 +- fn/oddEven.fn | 12 ++ src/common.h | 4 +- src/lambda_pp.c | 10 + src/main.c | 2 + src/print_compiler.c | 9 +- src/symbol.c | 68 +++++- src/symbol.h | 1 + src/tc_analyze.c | 493 +++++++++++++++++++++---------------------- src/tc_helper.c | 2 +- 11 files changed, 367 insertions(+), 269 deletions(-) create mode 100644 fn/bugs.fn create mode 100644 fn/oddEven.fn diff --git a/fn/bugs.fn b/fn/bugs.fn new file mode 100644 index 0000000..0e93bcf --- /dev/null +++ b/fn/bugs.fn @@ -0,0 +1,33 @@ +let + + // foldl :: (a -> b -> b) -> b -> list(a) -> b + // ((#cn) -> (#ym) -> #hn [#ym]) -> (#ym) -> (list(#cn)) -> #ym + // (a -> b -> b ) -> b -> list(a) -> b + fn foldl { + (_, acc, []) { acc } + (func, acc, h @ t) { foldl(func, func(h, acc), t) } + } + + // foldr :: (a -> b -> b) -> b -> list(a) -> b + // ((#nn) -> (#xn) -> #xn) -> (#xn) -> (#mn) -> #xn + // (a -> b -> b ) -> b -> ??? -> b + fn foldr(func, acc, lst) { + foldl(func, acc, reverse(lst)) + } + + // reverse :: list(#t) -> list(#t) + // (list(#no)) -> list(#no) + fn reverse (lst) { + foldl(fn (elem, acc) { elem @ acc }, [], lst) + } + + // BUG concat list of strings prints as a list of char rather than a string + // BUT if we define reverse before foldl it all works. + // concat :: list(list(#t)) -> list(#t) + // (380) -> list(<#t/421>395) + fn concat(lst) { + foldr(fn (elem, acc) { elem @@ acc }, [], lst) + } + +in + print(concat(["well", " ", "hi", " ", "there"])) diff --git a/fn/listutils.fn b/fn/listutils.fn index abad241..365f9fe 100644 --- a/fn/listutils.fn +++ b/fn/listutils.fn @@ -184,5 +184,5 @@ let } in - print(zipWith(fn (x, y) { x * y }, [1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12])); + print(concat(["well", " ", "hi", " ", "there"])); puts("\n") diff --git a/fn/oddEven.fn b/fn/oddEven.fn new file mode 100644 index 0000000..1a704d6 --- /dev/null +++ b/fn/oddEven.fn @@ -0,0 +1,12 @@ +let + fn odd { + (0) { false } + (n) { even(n - 1) } + } + fn even { + (0) { true } + (n) { odd(n - 1) } + } +in + print(odd(3)); + puts("\n") diff --git a/src/common.h b/src/common.h index 5726caf..a8512d1 100644 --- a/src/common.h +++ b/src/common.h @@ -35,7 +35,7 @@ typedef uint32_t hash_t; // #define DEBUG_TPMC_MATCH // #define DEBUG_TPMC_TRANSLATE // #define DEBUG_TPMC_LOGIC -// #define DEBUG_ANALIZE +// #define DEBUG_ANNOTATE // #define DEBUG_DESUGARING // #define DEBUG_HASHTABLE // #define DEBUG_TIN_SUBSTITUTION @@ -44,7 +44,7 @@ typedef uint32_t hash_t; // #define DEBUG_BYTECODE // define this to make fatal errors dump core (if ulimit allows) # define DEBUG_DUMP_CORE -// #define DEBUG_TC +# define DEBUG_TC // #define DEBUG_LAMBDA_CONVERT // #define DEBUG_LAMBDA_SUBSTITUTE // #define DEBUG_LEAK diff --git a/src/lambda_pp.c b/src/lambda_pp.c index ee641e2..69fc607 100644 --- a/src/lambda_pp.c +++ b/src/lambda_pp.c @@ -22,6 +22,7 @@ #include #include #include "lambda_pp.h" +void ppLamTag(LamExp *tag); void ppLamExpD(LamExp *exp, int depth) { while (depth > 0) { @@ -132,6 +133,9 @@ void ppLamExp(LamExp *exp) { case LAMEXP_TYPE_CONSTRUCT: ppLamConstruct(exp->val.construct); break; + case LAMEXP_TYPE_TAG: + ppLamTag(exp->val.tag); + break; case LAMEXP_TYPE_CONSTANT: ppLamConstant(exp->val.constant); break; @@ -637,6 +641,12 @@ void ppLamConstruct(LamConstruct *construct) { eprintf(")"); } +void ppLamTag(LamExp *tag) { + eprintf("(tag "); + ppLamExp(tag); + eprintf(")"); +} + void ppLamConstant(LamConstant *constant) { eprintf("(constant "); ppHashSymbol(constant->name); diff --git a/src/main.c b/src/main.c index c1ab8af..9faca8c 100644 --- a/src/main.c +++ b/src/main.c @@ -109,6 +109,8 @@ int main(int argc, char *argv[]) { } PROTECT(res); // normalization: LamExp => ANF + ppTcType(res); + eprintf("\n"); Exp *anfExp = anfNormalize(exp); PROTECT(anfExp); disableGC(); diff --git a/src/print_compiler.c b/src/print_compiler.c index 4677d25..2d8f6a6 100644 --- a/src/print_compiler.c +++ b/src/print_compiler.c @@ -44,6 +44,7 @@ static LamExp *compilePrinterForChar(); static LamExp *compilePrinterForUserType(TcUserType *userType, TcEnv *env); LamExp *compilePrinterForType(TcType *type, TcEnv *env) { + ENTER(compilePrinterForType); LamExp *res = NULL; switch (type->type) { case TCTYPE_TYPE_FUNCTION: @@ -69,6 +70,7 @@ LamExp *compilePrinterForType(TcType *type, TcEnv *env) { cant_happen("unrecognised TcType %d in compilePrinterForType", type->type); } + LEAVE(compilePrinterForType); return res; } @@ -98,14 +100,18 @@ static LamExp *compilePrinterForChar() { static LamList *compilePrinterForUserTypeArgs(TcUserTypeArgs *args, TcEnv *env) { - if (args == NULL) + ENTER(compilePrinterForUserTypeArgs); + if (args == NULL) { + LEAVE(compilePrinterForUserTypeArgs); return NULL; + } LamList *next = compilePrinterForUserTypeArgs(args->next, env); int save = PROTECT(next); LamExp *this = compilePrinterForType(args->type, env); PROTECT(this); LamList *res = newLamList(this, next); UNPROTECT(save); + LEAVE(compilePrinterForUserTypeArgs); return res; } @@ -115,6 +121,7 @@ static LamExp *compilePrinterForString() { } static LamExp *compilePrinterForUserType(TcUserType *userType, TcEnv *env) { + IFDEBUG(printTcUserType(userType, 0)); if (userType->name == listSymbol()) { if (userType->args && userType->args->type->type == TCTYPE_TYPE_CHARACTER) { diff --git a/src/symbol.c b/src/symbol.c index 758163b..aa48804 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -19,31 +19,75 @@ #include #include "symbol.h" +typedef enum GenSymFmt { + DECIMAL, + ALPHABETIC +} GenSymFmt; + // application-wide global symbol store static HashTable *symbolTable = NULL; +static HashTable *genSymTable = NULL; void markVarTable() { markHashTableObj((Header *) symbolTable); + markHashTableObj((Header *) genSymTable); } -HashSymbol *newSymbol(char *name) { +static void initSymbolTable() { if (symbolTable == NULL) { symbolTable = newHashTable(0, NULL, NULL); } +} + +static void initGenSymTable() { + if (genSymTable == NULL) { + genSymTable = newHashTable(sizeof(int), NULL, NULL); + } +} + +HashSymbol *newSymbol(char *name) { + initSymbolTable(); HashSymbol *res = uniqueHashSymbol(symbolTable, name, NULL); validateLastAlloc(); return res; } -HashSymbol *genSym(char *prefix) { - static int symbolCounter = 0; - char buffer[128]; - if (symbolTable == NULL) { - symbolTable = newHashTable(0, NULL, NULL); +HashSymbol *newSymbolCounter(char *baseName) { + initGenSymTable(); + HashSymbol *base = newSymbol(baseName); + if (!hashGet(genSymTable, base, NULL)) { + int i = 0; + hashSet(genSymTable, base, &i); } + return base; +} + +HashSymbol *_genSym(char *prefix, GenSymFmt fmt) { + int symbolCounter = 0; + char buffer[128]; + initSymbolTable(); + HashSymbol *base = newSymbolCounter(prefix); + hashGet(genSymTable, base, &symbolCounter); for (;;) { - sprintf(buffer, "%s%d", prefix, symbolCounter++); + switch (fmt) { + case DECIMAL: + sprintf(buffer, "%s%d", prefix, symbolCounter++); + break; + case ALPHABETIC:{ + char *alphabet = "abcdefghijklmnopqrstuvwxyz"; + char suffix[128]; + int index = 0; + int value = symbolCounter++; + while (value > 0) { + suffix[index++] = alphabet[value % 26]; + suffix[index] = '\0'; + value = value / 26; + } + sprintf(buffer, "%s%s", prefix, suffix); + } + break; + } if (hashGetVar(symbolTable, buffer) == NULL) { HashSymbol *x = NEW(HashSymbol, OBJTYPE_HASHSYMBOL); int save = PROTECT(x); @@ -51,8 +95,16 @@ HashSymbol *genSym(char *prefix) { x->hash = hashString(buffer); hashSet(symbolTable, x, NULL); UNPROTECT(save); - validateLastAlloc(); + hashSet(genSymTable, base, &symbolCounter); return x; } } } + +HashSymbol *genSym(char *prefix) { + return _genSym(prefix, DECIMAL); +} + +HashSymbol *genAlphaSym(char *prefix) { + return _genSym(prefix, ALPHABETIC); +} diff --git a/src/symbol.h b/src/symbol.h index ed31c11..ea93c63 100644 --- a/src/symbol.h +++ b/src/symbol.h @@ -21,6 +21,7 @@ # include "hash.h" HashSymbol *genSym(char *prefix); +HashSymbol *genAlphaSym(char *prefix); HashSymbol *newSymbol(char *name); diff --git a/src/tc_analyze.c b/src/tc_analyze.c index e84e814..829bd2b 100644 --- a/src/tc_analyze.c +++ b/src/tc_analyze.c @@ -46,7 +46,7 @@ static TcType *makeStarship(void); static TcType *makeSmallInteger(void); static TcType *makeBigInteger(void); static TcType *makeCharacter(void); -static TcType *makeFreshVar(char *); +static TcType *makeFreshVar(char *name __attribute__((unused))); static TcType *makeVar(HashSymbol *t); static TcType *makeFn(TcType *arg, TcType *result); static void addBoolBinOpToEnv(TcEnv *env, HashSymbol *symbol); @@ -86,7 +86,7 @@ static TcType *analyzeAmb(LamAmb *amb, TcEnv *env, TcNg *ng); static TcType *analyzeCharacter(); static TcType *analyzeBack(); static TcType *analyzeError(); -static bool unify(TcType *a, TcType *b); +static bool unify(TcType *a, TcType *b, char *trace __attribute__((unused))); static TcType *prune(TcType *t); static bool occursInType(TcType *a, TcType *b); static bool occursIn(TcType *a, TcType *b); @@ -134,8 +134,7 @@ TcEnv *tc_init(void) { TcType *tc_analyze(LamExp *exp, TcEnv *env) { TcNg *ng = extendNg(NULL); int save = PROTECT(ng); - IFDEBUG(ppLamExp(exp)); - TcType *res = prune(analyzeExp(exp, env, ng)); + TcType *res = analyzeExp(exp, env, ng); UNPROTECT(save); return res; } @@ -145,59 +144,59 @@ static TcType *analyzeExp(LamExp *exp, TcEnv *env, TcNg *ng) { return NULL; switch (exp->type) { case LAMEXP_TYPE_LAM: - return analyzeLam(exp->val.lam, env, ng); + return prune(analyzeLam(exp->val.lam, env, ng)); case LAMEXP_TYPE_VAR: - return analyzeVar(exp->val.var, env, ng); + return prune(analyzeVar(exp->val.var, env, ng)); case LAMEXP_TYPE_STDINT: - return analyzeSmallInteger(); + return prune(analyzeSmallInteger()); case LAMEXP_TYPE_BIGINTEGER: - return analyzeBigInteger(); + return prune(analyzeBigInteger()); case LAMEXP_TYPE_PRIM: - return analyzePrim(exp->val.prim, env, ng); + return prune(analyzePrim(exp->val.prim, env, ng)); case LAMEXP_TYPE_UNARY: - return analyzeUnary(exp->val.unary, env, ng); + return prune(analyzeUnary(exp->val.unary, env, ng)); case LAMEXP_TYPE_LIST: - return analyzeSequence(exp->val.list, env, ng); + return prune(analyzeSequence(exp->val.list, env, ng)); case LAMEXP_TYPE_MAKEVEC: cant_happen("encountered make-vec in analyzeExp"); case LAMEXP_TYPE_CONSTRUCT: - return analyzeConstruct(exp->val.construct, env, ng); + return prune(analyzeConstruct(exp->val.construct, env, ng)); case LAMEXP_TYPE_DECONSTRUCT: - return analyzeDeconstruct(exp->val.deconstruct, env, ng); + return prune(analyzeDeconstruct(exp->val.deconstruct, env, ng)); case LAMEXP_TYPE_TAG: - return analyzeTag(exp->val.tag, env, ng); + return prune(analyzeTag(exp->val.tag, env, ng)); case LAMEXP_TYPE_CONSTANT: - return analyzeConstant(exp->val.constant, env, ng); + return prune(analyzeConstant(exp->val.constant, env, ng)); case LAMEXP_TYPE_APPLY: - return analyzeApply(exp->val.apply, env, ng); + return prune(analyzeApply(exp->val.apply, env, ng)); case LAMEXP_TYPE_IFF: - return analyzeIff(exp->val.iff, env, ng); + return prune(analyzeIff(exp->val.iff, env, ng)); case LAMEXP_TYPE_CALLCC: - return analyzeCallCC(exp->val.callcc, env, ng); + return prune(analyzeCallCC(exp->val.callcc, env, ng)); case LAMEXP_TYPE_PRINT: - return analyzePrint(exp->val.print, env, ng); + return prune(analyzePrint(exp->val.print, env, ng)); case LAMEXP_TYPE_LETREC: - return analyzeLetRec(exp->val.letrec, env, ng); + return prune(analyzeLetRec(exp->val.letrec, env, ng)); case LAMEXP_TYPE_TYPEDEFS: - return analyzeTypeDefs(exp->val.typedefs, env, ng); + return prune(analyzeTypeDefs(exp->val.typedefs, env, ng)); case LAMEXP_TYPE_LET: - return analyzeLet(exp->val.let, env, ng); + return prune(analyzeLet(exp->val.let, env, ng)); case LAMEXP_TYPE_MATCH: - return analyzeMatch(exp->val.match, env, ng); + return prune(analyzeMatch(exp->val.match, env, ng)); case LAMEXP_TYPE_COND: - return analyzeCond(exp->val.cond, env, ng); + return prune(analyzeCond(exp->val.cond, env, ng)); case LAMEXP_TYPE_AND: - return analyzeAnd(exp->val.and, env, ng); + return prune(analyzeAnd(exp->val.and, env, ng)); case LAMEXP_TYPE_OR: - return analyzeOr(exp->val.or, env, ng); + return prune(analyzeOr(exp->val.or, env, ng)); case LAMEXP_TYPE_AMB: - return analyzeAmb(exp->val.amb, env, ng); + return prune(analyzeAmb(exp->val.amb, env, ng)); case LAMEXP_TYPE_CHARACTER: - return analyzeCharacter(); + return prune(analyzeCharacter()); case LAMEXP_TYPE_BACK: - return analyzeBack(); + return prune(analyzeBack()); case LAMEXP_TYPE_ERROR: - return analyzeError(); + return prune(analyzeError()); case LAMEXP_TYPE_COND_DEFAULT: cant_happen("encountered cond default in analyzeExp"); default: @@ -207,9 +206,9 @@ static TcType *analyzeExp(LamExp *exp, TcEnv *env, TcNg *ng) { static TcType *makeFunctionType(LamVarList *args, TcEnv *env, TcType *returnType) { - ENTER(makeFunctionType); + // ENTER(makeFunctionType); if (args == NULL) { - LEAVE(makeFunctionType); + // LEAVE(makeFunctionType); return returnType; } TcType *next = makeFunctionType(args->next, env, returnType); @@ -220,43 +219,38 @@ static TcType *makeFunctionType(LamVarList *args, TcEnv *env, } TcType *ret = makeFn(this, next); UNPROTECT(save); - LEAVE(makeFunctionType); + // LEAVE(makeFunctionType); return ret; } static TcType *analyzeLam(LamLam *lam, TcEnv *env, TcNg *ng) { - ENTER(analyzeLam); - IFDEBUG(ppLamLam(lam)); + // ENTER(analyzeLam); env = extendEnv(env); int save = PROTECT(env); ng = extendNg(ng); PROTECT(ng); for (LamVarList *args = lam->args; args != NULL; args = args->next) { - TcType *freshVar = makeFreshVar(args->var->name); - int save2 = PROTECT(freshVar); - addToEnv(env, args->var, freshVar); - addToNg(ng, freshVar->val.var->name, freshVar); + TcType *freshType = makeFreshVar(args->var->name); + int save2 = PROTECT(freshType); + addToEnv(env, args->var, freshType); + addToNg(ng, freshType->val.var->name, freshType); UNPROTECT(save2); } TcType *returnType = analyzeExp(lam->exp, env, ng); PROTECT(returnType); TcType *functionType = makeFunctionType(lam->args, env, returnType); UNPROTECT(save); - LEAVE(analyzeLam); - IFDEBUG(ppTcType(functionType)); + // LEAVE(analyzeLam); return functionType; } static TcType *analyzeVar(HashSymbol *var, TcEnv *env, TcNg *ng) { - ENTER(analyzeVar); - DEBUG("var: %s", var->name); + // ENTER(analyzeVar); TcType *res = lookup(env, var, ng); if (res == NULL) { can_happen("undefined variable %s in analyzeVar", var->name); } - LEAVE(analyzeVar); - DEBUG("var: %s", var->name); - IFDEBUG(ppTcType(res)); + // LEAVE(analyzeVar); return res; } @@ -265,36 +259,36 @@ static TcType *analyzeSmallInteger() { } static TcType *analyzeBigInteger() { - ENTER(analyzeBigInteger); + // ENTER(analyzeBigInteger); TcType *res = makeBigInteger(); - LEAVE(analyzeBigInteger); + // LEAVE(analyzeBigInteger); return res; } static TcType *analyzeBinaryArith(LamExp *exp1, LamExp *exp2, TcEnv *env, TcNg *ng) { - ENTER(analyzeBinaryArith); + // ENTER(analyzeBinaryArith); (void) analyzeBigIntegerExp(exp1, env, ng); TcType *res = analyzeBigIntegerExp(exp2, env, ng); - LEAVE(analyzeBinaryArith); + // LEAVE(analyzeBinaryArith); return res; } static TcType *analyzeUnaryArith(LamExp *exp, TcEnv *env, TcNg *ng) { - ENTER(analyzeBinaryArith); + // ENTER(analyzeBinaryArith); TcType *res = analyzeBigIntegerExp(exp, env, ng); - LEAVE(analyzeBinaryArith); + // LEAVE(analyzeBinaryArith); return res; } static TcType *analyzeComparison(LamExp *exp1, LamExp *exp2, TcEnv *env, TcNg *ng) { - ENTER(analyzeComparison); + // ENTER(analyzeComparison); TcType *type1 = analyzeExp(exp1, env, ng); int save = PROTECT(type1); TcType *type2 = analyzeExp(exp2, env, ng); PROTECT(type2); - if (!unify(type1, type2)) { + if (!unify(type1, type2, "comparison")) { eprintf("while unifying comparison:\n"); ppLamExp(exp1); eprintf("\nwith\n"); @@ -303,18 +297,18 @@ static TcType *analyzeComparison(LamExp *exp1, LamExp *exp2, TcEnv *env, } UNPROTECT(save); TcType *res = makeBoolean(); - LEAVE(analyzeComparison); + // LEAVE(analyzeComparison); return res; } static TcType *analyzeStarship(LamExp *exp1, LamExp *exp2, TcEnv *env, TcNg *ng) { - ENTER(analyzeComparison); + // ENTER(analyzeComparison); TcType *type1 = analyzeExp(exp1, env, ng); int save = PROTECT(type1); TcType *type2 = analyzeExp(exp2, env, ng); PROTECT(type2); - if (!unify(type1, type2)) { + if (!unify(type1, type2, "<=>")) { eprintf("while unifying <=>:\n"); ppLamExp(exp1); eprintf("\nwith\n"); @@ -323,35 +317,35 @@ static TcType *analyzeStarship(LamExp *exp1, LamExp *exp2, TcEnv *env, } UNPROTECT(save); TcType *res = makeStarship(); - LEAVE(analyzeComparison); + // LEAVE(analyzeComparison); return res; } static TcType *analyzeBinaryBool(LamExp *exp1, LamExp *exp2, TcEnv *env, TcNg *ng) { - ENTER(analyzeBinaryBool); + // ENTER(analyzeBinaryBool); (void) analyzeBooleanExp(exp1, env, ng); TcType *res = analyzeBooleanExp(exp2, env, ng); - LEAVE(analyzeBinaryBool); + // LEAVE(analyzeBinaryBool); return res; } static TcType *analyzeUnaryBool(LamExp *exp, TcEnv *env, TcNg *ng) { - ENTER(analyzeUnaryBool); + // ENTER(analyzeUnaryBool); TcType *res = analyzeBooleanExp(exp, env, ng); - LEAVE(analyzeUnaryBool); + // LEAVE(analyzeUnaryBool); return res; } static TcType *analyzeUnaryChar(LamExp *exp, TcEnv *env, TcNg *ng) { - ENTER(analyzeUnaryChar); + // ENTER(analyzeUnaryChar); TcType *res = analyzeCharacterExp(exp, env, ng); - LEAVE(analyzeUnaryChar); + // LEAVE(analyzeUnaryChar); return res; } static TcType *analyzePrim(LamPrimApp *app, TcEnv *env, TcNg *ng) { - ENTER(analyzePrim); + // ENTER(analyzePrim); TcType *res = NULL; switch (app->type) { case LAMPRIMOP_TYPE_ADD: @@ -382,12 +376,12 @@ static TcType *analyzePrim(LamPrimApp *app, TcEnv *env, TcNg *ng) { default: cant_happen("unrecognised type %d in analyzePrim", app->type); } - LEAVE(analyzePrim); + // LEAVE(analyzePrim); return res; } static TcType *analyzeUnary(LamUnaryApp *app, TcEnv *env, TcNg *ng) { - ENTER(analyzeUnary); + // ENTER(analyzeUnary); TcType *res = NULL; switch (app->type) { case LAMUNARYOP_TYPE_NEG: @@ -406,45 +400,44 @@ static TcType *analyzeUnary(LamUnaryApp *app, TcEnv *env, TcNg *ng) { default: cant_happen("unrecognized type %d in analyzeUnary", app->type); } - LEAVE(analyzeUnary); + // LEAVE(analyzeUnary); return res; } static TcType *analyzeSequence(LamSequence *sequence, TcEnv *env, TcNg *ng) { - ENTER(analyzeSequence); - IFDEBUG(ppLamSequence(sequence)); + // ENTER(analyzeSequence); if (sequence == NULL) { cant_happen("NULL sequence in analyzeSequence"); } TcType *type = analyzeExp(sequence->exp, env, ng); if (sequence->next != NULL) { TcType *res = analyzeSequence(sequence->next, env, ng); - LEAVE(analyzeSequence); + // LEAVE(analyzeSequence); return res; } - LEAVE(analyzeSequence); + // LEAVE(analyzeSequence); return type; } static LamApply *constructToApply(LamConstruct *construct) { - ENTER(constructToApply); + // ENTER(constructToApply); LamExp *constructor = newLamExp(LAMEXP_TYPE_VAR, LAMEXP_VAL_VAR(construct->name)); int save = PROTECT(constructor); LamApply *apply = newLamApply(constructor, countLamList(construct->args), construct->args); UNPROTECT(save); - LEAVE(constructToApply); + // LEAVE(constructToApply); return apply; } static TcType *analyzeConstruct(LamConstruct *construct, TcEnv *env, TcNg *ng) { - ENTER(analyzeConstruct); + // ENTER(analyzeConstruct); LamApply *apply = constructToApply(construct); int save = PROTECT(apply); TcType *res = analyzeApply(apply, env, ng); UNPROTECT(save); - LEAVE(analyzeConstruct); + // LEAVE(analyzeConstruct); return res; } @@ -475,30 +468,27 @@ static TcType *findResultType(TcType *fn) { static TcType *analyzeDeconstruct(LamDeconstruct *deconstruct, TcEnv *env, TcNg *ng) { - ENTER(analyzeDeconstruct); - IFDEBUG(ppLamDeconstruct(deconstruct)); + // ENTER(analyzeDeconstruct); TcType *constructor = lookup(env, deconstruct->name, ng); int save = PROTECT(constructor); if (constructor == NULL) { can_happen("undefined type deconstructor %s", deconstruct->name->name); TcType *res = makeFreshVar(deconstruct->name->name); - LEAVE(analyzeDeconstruct); + // LEAVE(analyzeDeconstruct); return res; } TcType *fieldType = findNthArg(deconstruct->vec - 1, constructor); TcType *resultType = findResultType(constructor); TcType *expType = analyzeExp(deconstruct->exp, env, ng); PROTECT(expType); - if (!unify(expType, resultType)) { + if (!unify(expType, resultType, "deconstruct")) { eprintf("while unifying deconstruct:\n"); ppLamDeconstruct(deconstruct); eprintf("\n"); } UNPROTECT(save); - LEAVE(analyzeDeconstruct); - IFDEBUG(ppTcType(fieldType)); - IFDEBUG(ppTcType(resultType)); + // LEAVE(analyzeDeconstruct); return fieldType; } @@ -507,15 +497,15 @@ static TcType *analyzeTag(LamExp *tagged, TcEnv *env, TcNg *ng) { } static TcType *analyzeConstant(LamConstant *constant, TcEnv *env, TcNg *ng) { - ENTER(analyzeConstant); + // ENTER(analyzeConstant); TcType *constType = lookup(env, constant->name, ng); if (constType == NULL) { can_happen("undefined constant %s", constant->name->name); TcType *res = makeFreshVar("err"); - LEAVE(analyzeConstant); + // LEAVE(analyzeConstant); return res; } - LEAVE(analyzeConstant); + // LEAVE(analyzeConstant); return constType; } @@ -544,30 +534,28 @@ static LamApply *curryLamApply(LamApply *apply) { } static TcType *analyzeApply(LamApply *apply, TcEnv *env, TcNg *ng) { - ENTER(analyzeApply); - IFDEBUG(ppLamApply(apply)); + // ENTER(analyzeApply); switch (apply->nargs) { case 0:{ - DEBUG("analyzeApply, nargs: 0"); TcType *res = analyzeExp(apply->function, env, ng); - LEAVE(analyzeApply); - IFDEBUG(ppLamApply(apply)); - IFDEBUG(ppTcType(res)); + // LEAVE(analyzeApply); return res; } case 1:{ - DEBUG("analyzeApply, nargs: 1"); + // fn :: #a -> #b TcType *fn = analyzeExp(apply->function, env, ng); int save = PROTECT(fn); - DEBUG("analyzeApply function is"); - IFDEBUG(ppTcType(fn)); + // arg :: #c TcType *arg = analyzeExp(apply->args->exp, env, ng); PROTECT(arg); + // res :: #d TcType *res = makeFreshVar("apply"); PROTECT(res); + // functionType :: #c -> #d TcType *functionType = makeFn(arg, res); PROTECT(functionType); - if (!unify(fn, functionType)) { + // unify(#a -> #b, #c -> #d) + if (!unify(fn, functionType, "apply")) { eprintf("while analyzing apply "); ppLamExp(apply->function); eprintf(" to "); @@ -575,33 +563,30 @@ static TcType *analyzeApply(LamApply *apply, TcEnv *env, TcNg *ng) { eprintf("\n"); } UNPROTECT(save); - LEAVE(analyzeApply); - IFDEBUG(ppLamApply(apply)); - IFDEBUG(ppTcType(res)); + // LEAVE(analyzeApply); + res = prune(res); + // #d/#b return res; } default:{ - DEBUG("analyzeApply, nargs: %d", apply->nargs); LamApply *curried = curryLamApply(apply); int save = PROTECT(curried); TcType *res = analyzeApply(curried, env, ng); UNPROTECT(save); - IFDEBUG(ppLamApply(apply)); - LEAVE(analyzeApply); - IFDEBUG(ppTcType(res)); + // LEAVE(analyzeApply); return res; } } } static TcType *analyzeIff(LamIff *iff, TcEnv *env, TcNg *ng) { - ENTER(analyzeIff); + // ENTER(analyzeIff); (void) analyzeBooleanExp(iff->condition, env, ng); TcType *consequent = analyzeExp(iff->consequent, env, ng); int save = PROTECT(consequent); TcType *alternative = analyzeExp(iff->alternative, env, ng); PROTECT(alternative); - if (!unify(consequent, alternative)) { + if (!unify(consequent, alternative, "iff")) { eprintf("while unifying consequent:\n"); ppLamExp(iff->consequent); eprintf("\nwith alternative:\n"); @@ -609,7 +594,7 @@ static TcType *analyzeIff(LamIff *iff, TcEnv *env, TcNg *ng) { eprintf("\n"); } UNPROTECT(save); - LEAVE(analyzeIff); + // LEAVE(analyzeIff); return consequent; } @@ -625,7 +610,7 @@ static TcType *analyzeCallCC(LamExp *called, TcEnv *env, TcNg *ng) { PROTECT(aba); TcType *calledType = analyzeExp(called, env, ng); PROTECT(calledType); - if (!unify(calledType, aba)) { + if (!unify(calledType, aba, "call/cc")) { eprintf("while unifying call/cc:\n"); ppLamExp(called); eprintf("\n"); @@ -636,10 +621,13 @@ static TcType *analyzeCallCC(LamExp *called, TcEnv *env, TcNg *ng) { static TcType *analyzePrint(LamPrint *print, TcEnv *env, TcNg *ng) { // a -> a, but installs a printer for type a + // ENTER(analyzePrint); TcType *type = analyzeExp(print->exp, env, ng); int save = PROTECT(type); print->printer = compilePrinterForType(type, env); UNPROTECT(save); + // LEAVE(analyzePrint); + IFDEBUG(ppTcType(type)); return type; } @@ -647,8 +635,34 @@ static bool isLambdaBinding(LamLetRecBindings *bindings) { return bindings->val->type == LAMEXP_TYPE_LAM; } +static void prepareLetRecEnv(LamLetRecBindings *bindings, TcEnv *env) { + TcType *freshType = makeFreshVar(bindings->var->name); + int save = PROTECT(freshType); + addToEnv(env, bindings->var, freshType); + UNPROTECT(save); +} + +static void processLetRecBinding(LamLetRecBindings *bindings, TcEnv *env, + TcNg *ng) { + TcType *freshType = NULL; + if (!getFromTcEnv(env, bindings->var, &freshType)) { + cant_happen("failed to retrieve fresh var from env in analyzeLetRec"); + } + int save = PROTECT(freshType); + // Recursive functions need to be statically typed inside their own context: + TcNg *ng2 = extendNg(ng); + PROTECT(ng2); + addToNg(ng2, freshType->val.var->name, freshType); + TcType *type = analyzeExp(bindings->val, env, ng2); + PROTECT(type); + unify(freshType, type, "letrec"); + DEBUGN("analyzeLetRec %s :: ", bindings->var->name); + IFDEBUGN(ppTcType(freshType)); + UNPROTECT(save); +} + static TcType *analyzeLetRec(LamLetRec *letRec, TcEnv *env, TcNg *ng) { - ENTER(analyzeLetRec); + // ENTER(analyzeLetRec); env = extendEnv(env); int save = PROTECT(env); ng = extendNg(ng); @@ -657,41 +671,28 @@ static TcType *analyzeLetRec(LamLetRec *letRec, TcEnv *env, TcNg *ng) { for (LamLetRecBindings *bindings = letRec->bindings; bindings != NULL; bindings = bindings->next) { if (isLambdaBinding(bindings)) { - TcType *freshVar = makeFreshVar(bindings->var->name); - int save2 = PROTECT(freshVar); - addToEnv(env, bindings->var, freshVar); - UNPROTECT(save2); + prepareLetRecEnv(bindings, env); } } for (LamLetRecBindings *bindings = letRec->bindings; bindings != NULL; bindings = bindings->next) { + DEBUGN("analyzeLetRec %s => ", bindings->var->name); + IFDEBUGN(ppLamExp(bindings->val)); if (!isLambdaBinding(bindings)) { - TcType *freshVar = makeFreshVar(bindings->var->name); - int save2 = PROTECT(freshVar); - addToEnv(env, bindings->var, freshVar); - UNPROTECT(save2); + prepareLetRecEnv(bindings, env); } - DEBUG("analyzeLetRec considering %s", bindings->var->name); - TcType *freshVar = NULL; - if (!getFromTcEnv(env, bindings->var, &freshVar)) { - cant_happen - ("failed to retrieve fresh var from env in analyzeLetRec"); + processLetRecBinding(bindings, env, ng); + } + // HACK! second pass through fixes up forward references + for (LamLetRecBindings *bindings = letRec->bindings; bindings != NULL; + bindings = bindings->next) { + if (isLambdaBinding(bindings)) { + processLetRecBinding(bindings, env, ng); } - int save2 = PROTECT(freshVar); - // Recursive functions need to be statically typed inside their own context: - TcNg *ng2 = extendNg(ng); - PROTECT(ng2); - addToNg(ng2, freshVar->val.var->name, freshVar); - TcType *type = analyzeExp(bindings->val, env, ng2); - PROTECT(type); - unify(freshVar, type); - DEBUG("analyzeLetRec binding %s, result:", bindings->var->name); - IFDEBUG(ppTcType(freshVar)); - UNPROTECT(save2); } TcType *res = analyzeExp(letRec->body, env, ng); UNPROTECT(save); - LEAVE(analyzeLetRec); + // LEAVE(analyzeLetRec); return res; } @@ -720,8 +721,6 @@ static TcType *makeUserType(HashSymbol *name, TcUserTypeArgs *args) { TcType *res = newTcType(TCTYPE_TYPE_USERTYPE, TCTYPE_VAL_USERTYPE(tcUserType)); UNPROTECT(save); - DEBUG("makeUserType: %s %p", name->name, res); - IFDEBUG(ppTcUserType(tcUserType)); return res; } @@ -829,23 +828,21 @@ static void collectTypeDef(LamTypeDef *lamTypeDef, TcEnv *env) { } static TcType *analyzeTypeDefs(LamTypeDefs *typeDefs, TcEnv *env, TcNg *ng) { - DEBUG("***************************************"); - ENTER(analyzeTypeDefs); + // ENTER(analyzeTypeDefs); env = extendEnv(env); int save = PROTECT(env); - DEBUG("after extendEnv:"); for (LamTypeDefList *list = typeDefs->typeDefs; list != NULL; list = list->next) { collectTypeDef(list->typeDef, env); } TcType *res = analyzeExp(typeDefs->body, env, ng); UNPROTECT(save); - LEAVE(analyzeTypeDefs); + // LEAVE(analyzeTypeDefs); return res; } static TcType *analyzeLet(LamLet *let, TcEnv *env, TcNg *ng) { - ENTER(analyzeLet); + // ENTER(analyzeLet); // let expression is evaluated in the current environment TcType *valType = analyzeExp(let->value, env, ng); int save = PROTECT(valType); @@ -854,197 +851,197 @@ static TcType *analyzeLet(LamLet *let, TcEnv *env, TcNg *ng) { addToEnv(env, let->var, valType); TcType *res = analyzeExp(let->body, env, ng); UNPROTECT(save); - LEAVE(analyzeLet); + // LEAVE(analyzeLet); return res; } static TcType *analyzeMatchCases(LamMatchList *cases, TcEnv *env, TcNg *ng) { - ENTER(analyzeMatchCases); + // ENTER(analyzeMatchCases); if (cases == NULL) { TcType *res = makeFreshVar("matchCases"); - LEAVE(analyzeMatchCases); + // LEAVE(analyzeMatchCases); return res; } TcType *rest = analyzeMatchCases(cases->next, env, ng); int save = PROTECT(rest); TcType *this = analyzeExp(cases->body, env, ng); PROTECT(this); - if (!unify(this, rest)) { + if (!unify(this, rest, "match cases")) { eprintf("while unifying match cases:\n"); ppLamExp(cases->body); eprintf("\n"); } UNPROTECT(save); - LEAVE(analyzeMatchCases); + // LEAVE(analyzeMatchCases); return this; } static TcType *analyzeBigIntegerExp(LamExp *exp, TcEnv *env, TcNg *ng) { - ENTER(analyzeBigIntegerExp); + // ENTER(analyzeBigIntegerExp); TcType *type = analyzeExp(exp, env, ng); int save = PROTECT(type); TcType *integer = makeBigInteger(); PROTECT(integer); - if (!unify(type, integer)) { + if (!unify(type, integer, "big integer exp")) { eprintf("while analyzing bigint expr:\n"); ppLamExp(exp); eprintf("\n"); } UNPROTECT(save); - LEAVE(analyzeBigIntegerExp); + // LEAVE(analyzeBigIntegerExp); return integer; } static TcType *analyzeSmallIntegerExp(LamExp *exp, TcEnv *env, TcNg *ng) { - ENTER(analyzeSmallIntegerExp); + // ENTER(analyzeSmallIntegerExp); TcType *type = analyzeExp(exp, env, ng); int save = PROTECT(type); TcType *integer = makeSmallInteger(); PROTECT(integer); - if (!unify(type, integer)) { + if (!unify(type, integer, "small integer exp")) { eprintf("while analyzing smallint expr:\n"); ppLamExp(exp); eprintf("\n"); } UNPROTECT(save); - LEAVE(analyzeSmallIntegerExp); + // LEAVE(analyzeSmallIntegerExp); return integer; } static TcType *analyzeBooleanExp(LamExp *exp, TcEnv *env, TcNg *ng) { - ENTER(analyzeBooleanExp); + // ENTER(analyzeBooleanExp); TcType *type = analyzeExp(exp, env, ng); int save = PROTECT(type); TcType *boolean = makeBoolean(); PROTECT(boolean); - if (!unify(type, boolean)) { + if (!unify(type, boolean, "boolean exp")) { eprintf("while analyzing boolean expr:\n"); ppLamExp(exp); eprintf("\n"); } UNPROTECT(save); - LEAVE(analyzeBooleanExp); + // LEAVE(analyzeBooleanExp); return boolean; } static TcType *analyzeCharacterExp(LamExp *exp, TcEnv *env, TcNg *ng) { - ENTER(analyzeCharacterExp); + // ENTER(analyzeCharacterExp); TcType *type = analyzeExp(exp, env, ng); int save = PROTECT(type); TcType *character = makeCharacter(); PROTECT(character); - if (!unify(type, character)) { + if (!unify(type, character, "character exp")) { eprintf("while analyzing character expr:\n"); ppLamExp(exp); eprintf("\n"); } UNPROTECT(save); - LEAVE(analyzeCharacterExp); + // LEAVE(analyzeCharacterExp); return character; } static TcType *lookupConstructorType(HashSymbol *name, TcEnv *env, TcNg *ng) { - ENTER(lookupConstructorType); + // ENTER(lookupConstructorType); TcType *res = lookup(env, name, ng); if (res == NULL) { cant_happen("lookupConstructorType %s failed", name->name); } res = findResultType(res); - LEAVE(lookupConstructorType); + // LEAVE(lookupConstructorType); return res; } static TcType *analyzeIntList(LamIntList *intList, TcEnv *env, TcNg *ng) { - ENTER(analyzeIntList); + // ENTER(analyzeIntList); if (intList == NULL) { - LEAVE(analyzeIntList); + // LEAVE(analyzeIntList); return makeFreshVar("intList"); } TcType *next = analyzeIntList(intList->next, env, ng); int save = PROTECT(next); TcType *this = lookupConstructorType(intList->name, env, ng); PROTECT(this); - if (!unify(next, this)) { + if (!unify(next, this, "int list")) { eprintf("while analyzing intList case %s\n", intList->name->name); } - LEAVE(analyzeIntList); + // LEAVE(analyzeIntList); UNPROTECT(save); return this; } static TcType *findCaseType(LamMatchList *matchList, TcEnv *env, TcNg *ng) { - ENTER(findCaseType); + // ENTER(findCaseType); if (matchList == NULL) { - LEAVE(findCaseType); + // LEAVE(findCaseType); return makeFreshVar("caseType"); } TcType *next = findCaseType(matchList->next, env, ng); int save = PROTECT(next); TcType *this = analyzeIntList(matchList->matches, env, ng); PROTECT(this); - if (!unify(this, next)) { + if (!unify(this, next, "find case type")) { eprintf("while finding case type\n"); } UNPROTECT(save); - LEAVE(findCaseType); + // LEAVE(findCaseType); return this; } static TcType *analyzeMatch(LamMatch *match, TcEnv *env, TcNg *ng) { - ENTER(analyzeMatch); + // ENTER(analyzeMatch); TcType *caseType = findCaseType(match->cases, env, ng); int save = PROTECT(caseType); TcType *indexType = analyzeExp(match->index, env, ng); PROTECT(indexType); - if (!unify(caseType, indexType)) { + if (!unify(caseType, indexType, "match")) { eprintf("while analyzing match\n"); } TcType *res = analyzeMatchCases(match->cases, env, ng); - LEAVE(analyzeMatch); + // LEAVE(analyzeMatch); UNPROTECT(save); return res; } static TcType *analyzeIntCondCases(LamIntCondCases *cases, TcEnv *env, TcNg *ng) { - ENTER(analyzeIntCondCases); + // ENTER(analyzeIntCondCases); if (cases == NULL) { - LEAVE(analyzeIntCondCases); + // LEAVE(analyzeIntCondCases); return makeFreshVar("intCondCases"); } TcType *rest = analyzeIntCondCases(cases->next, env, ng); int save = PROTECT(rest); TcType *this = analyzeExp(cases->body, env, ng); PROTECT(this); - if (!unify(this, rest)) { + if (!unify(this, rest, "cond cases")) { eprintf("while analyzing int cond cases\n"); } UNPROTECT(save); - LEAVE(analyzeIntCondCases); + // LEAVE(analyzeIntCondCases); return this; } static TcType *analyzeCharCondCases(LamCharCondCases *cases, TcEnv *env, TcNg *ng) { - ENTER(analyzeCharCondCases); + // ENTER(analyzeCharCondCases); if (cases == NULL) { - LEAVE(analyzeCharCondCases); + // LEAVE(analyzeCharCondCases); return makeFreshVar("charCondCases"); } TcType *rest = analyzeCharCondCases(cases->next, env, ng); int save = PROTECT(rest); TcType *this = analyzeExp(cases->body, env, ng); PROTECT(this); - if (!unify(this, rest)) { + if (!unify(this, rest, "char cond cases")) { eprintf("while analyzing char cond cases\n"); } UNPROTECT(save); - LEAVE(analyzeCharCondCases); + // LEAVE(analyzeCharCondCases); return this; } static TcType *analyzeCond(LamCond *cond, TcEnv *env, TcNg *ng) { - ENTER(analyzeCond); + // ENTER(analyzeCond); TcType *result = NULL; int save = PROTECT(result); TcType *value = analyzeExp(cond->value, env, ng); @@ -1053,7 +1050,7 @@ static TcType *analyzeCond(LamCond *cond, TcEnv *env, TcNg *ng) { case LAMCONDCASES_TYPE_INTEGERS:{ TcType *integer = makeBigInteger(); PROTECT(integer); - if (!unify(value, integer)) { + if (!unify(value, integer, "cond[1]")) { eprintf("while analyzing integer cond:\n"); ppLamExp(cond->value); eprintf("\n"); @@ -1065,7 +1062,7 @@ static TcType *analyzeCond(LamCond *cond, TcEnv *env, TcNg *ng) { case LAMCONDCASES_TYPE_CHARACTERS:{ TcType *character = makeCharacter(); PROTECT(character); - if (!unify(value, character)) { + if (!unify(value, character, "cond[2]")) { eprintf("while analyzing character cond:\n"); ppLamExp(cond->value); eprintf("\n"); @@ -1080,31 +1077,31 @@ static TcType *analyzeCond(LamCond *cond, TcEnv *env, TcNg *ng) { cond->cases->type); } UNPROTECT(save); - LEAVE(analyzeCond); + // LEAVE(analyzeCond); return result; } static TcType *analyzeAnd(LamAnd *and, TcEnv *env, TcNg *ng) { - ENTER(analyzeAnd); + // ENTER(analyzeAnd); TcType *res = analyzeBinaryBool(and->left, and->right, env, ng); - LEAVE(analyzeAnd); + // LEAVE(analyzeAnd); return res; } static TcType *analyzeOr(LamOr *or, TcEnv *env, TcNg *ng) { - ENTER(analyzeOr); + // ENTER(analyzeOr); TcType *res = analyzeBinaryBool(or->left, or->right, env, ng); - LEAVE(analyzeOr); + // LEAVE(analyzeOr); return res; } static TcType *analyzeAmb(LamAmb *amb, TcEnv *env, TcNg *ng) { - ENTER(analyzeAmb); + // ENTER(analyzeAmb); TcType *left = analyzeExp(amb->left, env, ng); int save = PROTECT(left); TcType *right = analyzeExp(amb->right, env, ng); PROTECT(right); - if (!unify(left, right)) { + if (!unify(left, right, "amb")) { eprintf("while unifying amb:\n"); ppLamExp(amb->left); eprintf("\nwith:\n"); @@ -1112,34 +1109,32 @@ static TcType *analyzeAmb(LamAmb *amb, TcEnv *env, TcNg *ng) { eprintf("\n"); } UNPROTECT(save); - LEAVE(analyzeAmb); + // LEAVE(analyzeAmb); return left; } static TcType *analyzeCharacter() { - ENTER(analyzeCharacter); + // ENTER(analyzeCharacter); TcType *res = makeCharacter(); - LEAVE(analyzeCharacter); + // LEAVE(analyzeCharacter); return res; } static TcType *analyzeBack() { - ENTER(analyzeBack); + // ENTER(analyzeBack); TcType *res = makeFreshVar("back"); - LEAVE(analyzeBack); + // LEAVE(analyzeBack); return res; } static TcType *analyzeError() { - ENTER(analyzeError); + // ENTER(analyzeError); TcType *res = makeFreshVar("error"); - LEAVE(analyzeError); + // LEAVE(analyzeError); return res; } static void addToEnv(TcEnv *env, HashSymbol *symbol, TcType *type) { - DEBUG("addToEnv %s =>", symbol->name); - IFDEBUG(ppTcType(type)); setTcTypeTable(env->table, symbol, type); } @@ -1168,7 +1163,6 @@ static TcType *makePair(TcType *first, TcType *second) { int save = PROTECT(resPair); TcType *res = newTcType(TCTYPE_TYPE_PAIR, TCTYPE_VAL_PAIR(resPair)); UNPROTECT(save); - DEBUG("makePair: %p", res); return res; } @@ -1196,36 +1190,25 @@ static TcUserTypeArgs *freshUserTypeArgs(TcUserTypeArgs *args, TcNg *ng, } static TcType *freshUserType(TcUserType *userType, TcNg *ng, TcTypeTable *map) { - ENTER(freshUserType); TcUserTypeArgs *args = freshUserTypeArgs(userType->args, ng, map); int save = PROTECT(args); TcType *res = makeUserType(userType->name, args); UNPROTECT(save); - LEAVE(freshUserType); - IFDEBUG(ppTcUserType(userType)); - IFDEBUG(ppTcType(res)); return res; } static bool isGeneric(TcType *typeVar, TcNg *ng) { - ENTER(isGeneric); - IFDEBUG(ppTcType(typeVar)); - IFDEBUG(printTcNg(ng, 0)); while (ng != NULL) { int i = 0; TcType *entry = NULL; HashSymbol *s = NULL; while ((s = iterateTcTypeTable(ng->table, &i, &entry)) != NULL) { if (occursInType(typeVar, entry)) { - LEAVE(isGeneric); - DEBUG("false"); return false; } } ng = ng->next; } - LEAVE(isGeneric); - DEBUG("true"); return true; } @@ -1252,9 +1235,9 @@ static TcType *freshRec(TcType *type, TcNg *ng, TcTypeTable *map) { } case TCTYPE_TYPE_VAR: if (isGeneric(type, ng)) { - TcType *freshVar = makeFreshVar(type->val.var->name->name); - int save = PROTECT(freshVar); - TcType *res = typeGetOrPut(map, type, freshVar); + TcType *freshType = makeFreshVar(type->val.var->name->name); + int save = PROTECT(freshType); + TcType *res = typeGetOrPut(map, type, freshType); UNPROTECT(save); return res; } @@ -1273,35 +1256,31 @@ static TcType *freshRec(TcType *type, TcNg *ng, TcTypeTable *map) { } static TcType *fresh(TcType *type, TcNg *ng) { - ENTER(fresh); - IFDEBUG(ppTcType(type)); + // ENTER(fresh); TcTypeTable *map = newTcTypeTable(); int save = PROTECT(map); TcType *res = freshRec(type, ng, map); UNPROTECT(save); - LEAVE(fresh); - IFDEBUG(ppTcType(res)); + // LEAVE(fresh); return res; } static TcType *lookup(TcEnv *env, HashSymbol *symbol, TcNg *ng) { - ENTER(lookup); - DEBUG("lookup: %s", symbol->name); + // ENTER(lookup); TcType *type = NULL; if (getFromTcEnv(env, symbol, &type)) { TcType *res = fresh(type, ng); - LEAVE(lookup); - IFDEBUG(ppTcType(res)); + // LEAVE(lookup); + DEBUGN("lookup %s => ", symbol->name); + IFDEBUGN(ppTcType(res)); return res; } - LEAVE(lookup); - DEBUG("NULL"); + // LEAVE(lookup); + DEBUG("lookup %s => NULL", symbol->name); return NULL; } static void addToNg(TcNg *ng, HashSymbol *symbol, TcType *type) { - DEBUG("addToNg %s =>", symbol->name); - IFDEBUG(ppTcType(type)); setTcTypeTable(ng->table, symbol, type); } @@ -1316,12 +1295,13 @@ static TcType *makeStarship() { } static TcType *makeFn(TcType *arg, TcType *result) { + arg = prune(arg); + result = prune(result); TcFunction *fn = newTcFunction(arg, result); int save = PROTECT(fn); assert(fn != NULL); TcType *type = newTcType(TCTYPE_TYPE_FUNCTION, TCTYPE_VAL_FUNCTION(fn)); UNPROTECT(save); - DEBUG("makeFunction: %p", type); return type; } @@ -1340,32 +1320,26 @@ static TcType *makeVar(HashSymbol *t) { int save = PROTECT(var); TcType *res = newTcType(TCTYPE_TYPE_VAR, TCTYPE_VAL_VAR(var)); UNPROTECT(save); - DEBUG("makeVar %s %p", t->name, res); return res; } -static TcType *makeFreshVar(char *name) { - static char buff[256]; - snprintf(buff, 256, "%s/", name); - return makeVar(genSym(buff)); +static TcType *makeFreshVar(char *name __attribute__((unused))) { + return makeVar(genAlphaSym("#")); } static TcType *makeSmallInteger() { TcType *res = newTcType(TCTYPE_TYPE_SMALLINTEGER, TCTYPE_VAL_SMALLINTEGER()); - DEBUG("makeSmallInteger %p", res); return res; } static TcType *makeBigInteger() { TcType *res = newTcType(TCTYPE_TYPE_BIGINTEGER, TCTYPE_VAL_BIGINTEGER()); - DEBUG("makeBigInteger %p", res); return res; } static TcType *makeCharacter() { TcType *res = newTcType(TCTYPE_TYPE_CHARACTER, TCTYPE_VAL_CHARACTER()); - DEBUG("makeCharacter %p", res); return res; } @@ -1431,13 +1405,13 @@ static void addHereToEnv(TcEnv *env) { static void addCmpToEnv(TcEnv *env, HashSymbol *symbol) { // all binary comparisons are a -> a -> bool - TcType *freshVar = makeFreshVar(symbol->name); - int save = PROTECT(freshVar); + TcType *freshType = makeFreshVar(symbol->name); + int save = PROTECT(freshType); TcType *boolean = makeBoolean(); (void) PROTECT(boolean); - TcType *unOp = makeFn(freshVar, boolean); + TcType *unOp = makeFn(freshType, boolean); (void) PROTECT(unOp); - TcType *binOp = makeFn(freshVar, unOp); + TcType *binOp = makeFn(freshType, unOp); (void) PROTECT(binOp); addToEnv(env, symbol, binOp); UNPROTECT(save); @@ -1445,9 +1419,9 @@ static void addCmpToEnv(TcEnv *env, HashSymbol *symbol) { static void addFreshVarToEnv(TcEnv *env, HashSymbol *symbol) { // 'error' and 'back' both have unconstrained types - TcType *freshVar = makeFreshVar(symbol->name); - int save = PROTECT(freshVar); - addToEnv(env, symbol, freshVar); + TcType *freshType = makeFreshVar(symbol->name); + int save = PROTECT(freshType); + addToEnv(env, symbol, freshType); UNPROTECT(save); } @@ -1479,19 +1453,21 @@ static void addBoolBinOpToEnv(TcEnv *env, HashSymbol *symbol) { static void addThenToEnv(TcEnv *env) { // a -> a -> a - TcType *freshVar = makeFreshVar("then"); - int save = PROTECT(freshVar); - addBinOpToEnv(env, thenSymbol(), freshVar); + TcType *freshType = makeFreshVar("then"); + int save = PROTECT(freshType); + addBinOpToEnv(env, thenSymbol(), freshType); UNPROTECT(save); } static bool unifyFunctions(TcFunction *a, TcFunction *b) { - bool res = unify(a->arg, b->arg) && unify(a->result, b->result); + bool res = unify(a->arg, b->arg, "functions[arg]") + && unify(a->result, b->result, "functions[result]"); return res; } static bool unifyPairs(TcPair *a, TcPair *b) { - bool res = unify(a->first, b->first) && unify(a->second, b->second); + bool res = unify(a->first, b->first, "pairs[first]") + && unify(a->second, b->second, "pairs[second]"); return res; } @@ -1507,7 +1483,7 @@ static bool unifyUserTypes(TcUserType *a, TcUserType *b) { TcUserTypeArgs *aArgs = a->args; TcUserTypeArgs *bArgs = b->args; while (aArgs != NULL && bArgs != NULL) { - if (!unify(aArgs->type, bArgs->type)) { + if (!unify(aArgs->type, bArgs->type, "user types")) { return false; } aArgs = aArgs->next; @@ -1524,13 +1500,9 @@ static bool unifyUserTypes(TcUserType *a, TcUserType *b) { return true; } -static bool unify(TcType *a, TcType *b) { +static bool _unify(TcType *a, TcType *b) { a = prune(a); b = prune(b); - DEBUG("UNIFY"); - // *INDENT-OFF* - IFDEBUG(ppTcType(a); eprintf(" WITH "); ppTcType(b)); - // *INDENT-ON* if (a == b) return true; if (a->type == TCTYPE_TYPE_VAR) { @@ -1539,19 +1511,15 @@ static bool unify(TcType *a, TcType *b) { can_happen("occurs-in check failed"); return false; } - DEBUG("unify combining"); a->val.var->instance = b; - IFDEBUG(ppTcType(a)); return true; } if (a->val.var->name != b->val.var->name) { - DEBUG("unify combining"); a->val.var->instance = b; - IFDEBUG(ppTcType(a)); } return true; } else if (b->type == TCTYPE_TYPE_VAR) { - return unify(b, a); + return unify(b, a, "unify"); } else { if (a->type != b->type) { can_happen("unification failed[3]"); @@ -1581,6 +1549,19 @@ static bool unify(TcType *a, TcType *b) { cant_happen("reached end of unify"); } +static bool unify(TcType *a, TcType *b, char *trace __attribute__((unused))) { + DEBUGN("unify(%s) :> ", trace); + IFDEBUGN(ppTcType(a); + eprintf(" =?= "); + ppTcType(b)); + bool res = _unify(a, b); + DEBUGN("unify(%s) <: ", trace); + IFDEBUGN(ppTcType(a); + eprintf(" === "); + ppTcType(b)); + return res; +} + static void pruneUserTypeArgs(TcUserTypeArgs *args) { while (args != NULL) { args->type = prune(args->type); diff --git a/src/tc_helper.c b/src/tc_helper.c index def80bd..48fa050 100644 --- a/src/tc_helper.c +++ b/src/tc_helper.c @@ -67,7 +67,7 @@ void ppTcPair(TcPair *pair) { } void ppTcVar(TcVar *var) { - eprintf("<%s>%d", var->name->name, var->id); + eprintf("%s", var->name->name); if (var->instance != NULL) { eprintf(" ["); ppTcType(var->instance); From d0f096b228996164fab97ca716adbea23fb5e592 Mon Sep 17 00:00:00 2001 From: Bill Hails Date: Sat, 16 Mar 2024 14:47:37 +0000 Subject: [PATCH 22/33] split main, simplified tc_analyze --- src/common.h | 2 +- src/main.c | 107 ++++++++++++++++++++++++++++++++--------------- src/tc_analyze.c | 35 +++++++++------- 3 files changed, 93 insertions(+), 51 deletions(-) diff --git a/src/common.h b/src/common.h index a8512d1..cb42ee1 100644 --- a/src/common.h +++ b/src/common.h @@ -44,7 +44,7 @@ typedef uint32_t hash_t; // #define DEBUG_BYTECODE // define this to make fatal errors dump core (if ulimit allows) # define DEBUG_DUMP_CORE -# define DEBUG_TC +// # define DEBUG_TC // #define DEBUG_LAMBDA_CONVERT // #define DEBUG_LAMBDA_SUBSTITUTE // #define DEBUG_LEAK diff --git a/src/main.c b/src/main.c index 9faca8c..aef3069 100644 --- a/src/main.c +++ b/src/main.c @@ -46,9 +46,8 @@ int report_flag = 0; static int help_flag = 0; -int main(int argc, char *argv[]) { +static void processArgs(int argc, char *argv[]) { int c; - clock_t begin = clock(); while (1) { static struct option long_options[] = { @@ -73,65 +72,73 @@ int main(int argc, char *argv[]) { exit(0); } - ByteCodeArray byteCodes; - initProtection(); - disableGC(); - /* - printf("char: %ld\n", sizeof(char)); - printf("word: %ld\n", sizeof(word)); - printf("int: %ld\n", sizeof(int)); - printf("bigint_word: %ld\n", sizeof(bigint_word)); - printf("void *: %ld\n", sizeof(void *)); - */ - if (optind >= argc) { eprintf("need filename\n"); exit(1); } - // parse => AST - PmModule *mod = newPmToplevelFromFile(argv[optind]); - PROTECT(mod); +} + +static AstNest *parseFile(char *file) { + disableGC(); + PmModule *mod = newPmToplevelFromFile(file); + int save = PROTECT(mod); pmParseModule(mod); enableGC(); - // lambda conversion: AST => LamExp - LamExp *exp = lamConvertNest(mod->nest, NULL); + UNPROTECT(save); + return mod->nest; +} + +static LamExp *convertNest(AstNest *nest) { + LamExp *exp = lamConvertNest(nest, NULL); int save = PROTECT(exp); #ifdef DEBUG_LAMBDA_CONVERT ppLamExp(exp); eprintf("\n"); #endif - // type checking + UNPROTECT(save); + return exp; +} + +static void typeCheck(LamExp *exp) { TcEnv *env = tc_init(); - PROTECT(env); - TcType *res = tc_analyze(exp, env); + int save = PROTECT(env); + TcType *res __attribute__((unused)) = tc_analyze(exp, env); if (hadErrors()) { - return 1; + exit(1); } - PROTECT(res); - // normalization: LamExp => ANF +#ifdef DEBUG_TC ppTcType(res); eprintf("\n"); - Exp *anfExp = anfNormalize(exp); - PROTECT(anfExp); +#endif + UNPROTECT(save); +} + +static Exp *desugar(Exp *anfExp) { disableGC(); - // desugaring anfExp = desugarExp(anfExp); - PROTECT(anfExp); + int save = PROTECT(anfExp); enableGC(); - // static analysis: ANF => annotated ANF (de bruijn) + UNPROTECT(save); + return anfExp; +} + +static void annotate(Exp *anfExp) { annotateExp(anfExp, NULL); #ifdef DEBUG_ANF ppExp(anfExp); eprintf("\n"); #endif - // byte code generation +} + +static ByteCodeArray generateByteCodes(Exp *anfExp) { + ByteCodeArray byteCodes; initByteCodeArray(&byteCodes); writeExp(anfExp, &byteCodes); writeEnd(&byteCodes); - UNPROTECT(save); - // execution - run(byteCodes); - // report stats etc. + return byteCodes; +} + +static void report(clock_t begin) { if (report_flag) { clock_t end = clock(); double time_spent = (double) (end - begin) / CLOCKS_PER_SEC; @@ -140,3 +147,35 @@ int main(int argc, char *argv[]) { reportSteps(); } } + +int main(int argc, char *argv[]) { + clock_t begin = clock(); + processArgs(argc, argv); + initProtection(); + + AstNest *nest = parseFile(argv[optind]); + int save = PROTECT(nest); + + LamExp *exp = convertNest(nest); + REPLACE_PROTECT(save, exp); + + typeCheck(exp); + + Exp *anfExp = anfNormalize(exp); + REPLACE_PROTECT(save, anfExp); + + anfExp = desugar(anfExp); + REPLACE_PROTECT(save, anfExp); + + annotate(anfExp); + + ByteCodeArray byteCodes = generateByteCodes(anfExp); + + UNPROTECT(save); + + run(byteCodes); + + report(begin); + + exit(0); +} diff --git a/src/tc_analyze.c b/src/tc_analyze.c index 829bd2b..8e440c1 100644 --- a/src/tc_analyze.c +++ b/src/tc_analyze.c @@ -38,7 +38,7 @@ static TcEnv *extendEnv(TcEnv *parent); static TcNg *extendNg(TcNg *parent); static void addToEnv(TcEnv *env, HashSymbol *key, TcType *type); -static void addToNg(TcNg *env, HashSymbol *symbol, TcType *type); +static void addToNg(TcNg *env, TcType *type); static void addFreshVarToEnv(TcEnv *env, HashSymbol *key); static void addCmpToEnv(TcEnv *env, HashSymbol *key); static TcType *makeBoolean(void); @@ -233,7 +233,7 @@ static TcType *analyzeLam(LamLam *lam, TcEnv *env, TcNg *ng) { TcType *freshType = makeFreshVar(args->var->name); int save2 = PROTECT(freshType); addToEnv(env, args->var, freshType); - addToNg(ng, freshType->val.var->name, freshType); + addToNg(ng, freshType); UNPROTECT(save2); } TcType *returnType = analyzeExp(lam->exp, env, ng); @@ -644,20 +644,20 @@ static void prepareLetRecEnv(LamLetRecBindings *bindings, TcEnv *env) { static void processLetRecBinding(LamLetRecBindings *bindings, TcEnv *env, TcNg *ng) { - TcType *freshType = NULL; - if (!getFromTcEnv(env, bindings->var, &freshType)) { + TcType *existingType = NULL; + if (!getFromTcEnv(env, bindings->var, &existingType)) { cant_happen("failed to retrieve fresh var from env in analyzeLetRec"); } - int save = PROTECT(freshType); + int save = PROTECT(existingType); // Recursive functions need to be statically typed inside their own context: TcNg *ng2 = extendNg(ng); PROTECT(ng2); - addToNg(ng2, freshType->val.var->name, freshType); + addToNg(ng2, existingType); TcType *type = analyzeExp(bindings->val, env, ng2); PROTECT(type); - unify(freshType, type, "letrec"); + unify(existingType, type, "letrec"); DEBUGN("analyzeLetRec %s :: ", bindings->var->name); - IFDEBUGN(ppTcType(freshType)); + IFDEBUGN(ppTcType(existingType)); UNPROTECT(save); } @@ -1280,8 +1280,13 @@ static TcType *lookup(TcEnv *env, HashSymbol *symbol, TcNg *ng) { return NULL; } -static void addToNg(TcNg *ng, HashSymbol *symbol, TcType *type) { - setTcTypeTable(ng->table, symbol, type); +static void addToNg(TcNg *ng, TcType *type) { +#ifdef SAFETY_CHECKS + if (type->type != TCTYPE_TYPE_VAR) { + cant_happen("non-var type passed to addToNg"); + } +#endif + setTcTypeTable(ng->table, type->val.var->name, type); } static TcType *makeBoolean() { @@ -1550,16 +1555,14 @@ static bool _unify(TcType *a, TcType *b) { } static bool unify(TcType *a, TcType *b, char *trace __attribute__((unused))) { + // *INDENT-OFF* DEBUGN("unify(%s) :> ", trace); - IFDEBUGN(ppTcType(a); - eprintf(" =?= "); - ppTcType(b)); + IFDEBUGN(ppTcType(a); eprintf(" =?= "); ppTcType(b)); bool res = _unify(a, b); DEBUGN("unify(%s) <: ", trace); - IFDEBUGN(ppTcType(a); - eprintf(" === "); - ppTcType(b)); + IFDEBUGN(ppTcType(a); eprintf(" === "); ppTcType(b)); return res; + // *INDENT-ON* } static void pruneUserTypeArgs(TcUserTypeArgs *args) { From 1d9b2a5b8bf28a0f7296e2a906b9c3795a99f2a3 Mon Sep 17 00:00:00 2001 From: Bill Hails Date: Sat, 16 Mar 2024 15:21:41 +0000 Subject: [PATCH 23/33] forgot to fix the tests --- Makefile | 2 +- fn/pythagoreanTriples.fn | 6 ++---- src/common.h | 4 ++-- tests/src/test_typechecker.c | 18 +++++++++--------- 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/Makefile b/Makefile index 5b9fe34..b7d99d7 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ MODE_P=-pg MODE_O=-O2 MODE_D=-g -DDEBUG_ANY -CCMODE = $(MODE_D) +CCMODE = $(MODE_O) CC=cc -Wall -Wextra -Werror $(CCMODE) LAXCC=cc -Werror $(CCMODE) diff --git a/fn/pythagoreanTriples.fn b/fn/pythagoreanTriples.fn index 62b83b2..aa37497 100644 --- a/fn/pythagoreanTriples.fn +++ b/fn/pythagoreanTriples.fn @@ -3,8 +3,6 @@ let condition or back } - fn square(x) { x * x } - fn integers_from(n) { n then integers_from(n + 1) } @@ -20,7 +18,7 @@ let x = integers_between(1, z); y = integers_between(x, z); in - require(square(x) + square(y) == square(z)); + require(x**2 + y**2 == z**2); [x, y, z] } in { @@ -28,5 +26,5 @@ in { in print(triple); puts("\n"); - require( 20) // until + require( 50) // until } diff --git a/src/common.h b/src/common.h index cb42ee1..bc3a352 100644 --- a/src/common.h +++ b/src/common.h @@ -29,7 +29,7 @@ typedef uint32_t hash_t; // if DEBUG_STEP is defined, this sleeps for 1 second between each machine step // #define DEBUG_SLOW_STEP // define this to cause a GC at every malloc (catches memory leaks early) -# define DEBUG_STRESS_GC +// # define DEBUG_STRESS_GC // #define DEBUG_LOG_GC // #define DEBUG_GC // #define DEBUG_TPMC_MATCH @@ -53,7 +53,7 @@ typedef uint32_t hash_t; // #define DEBUG_PRINT_GENERATOR // #define DEBUG_PRINT_COMPILER // define this to turn on additional safety checks for things that shouldn't but just possibly might happen -# define SAFETY_CHECKS +// # define SAFETY_CHECKS # endif # ifndef __GNUC__ diff --git a/tests/src/test_typechecker.c b/tests/src/test_typechecker.c index 0cf19bc..d38d52f 100644 --- a/tests/src/test_typechecker.c +++ b/tests/src/test_typechecker.c @@ -60,19 +60,19 @@ static TcType *makeVar(char *name) { return var; } -static TcType *makeTypeDef(char *name, TcTypeDefArgs *args) { +static TcType *makeUserType(char *name, TcUserTypeArgs *args) { HashSymbol *sym = newSymbol(name); - TcTypeDef *typeDef = newTcTypeDef(sym, args); + TcUserType *typeDef = newTcUserType(sym, args); int save = PROTECT(typeDef); - TcType *td = newTcType(TCTYPE_TYPE_TYPEDEF, TCTYPE_VAL_TYPEDEF(typeDef)); + TcType *td = newTcType(TCTYPE_TYPE_USERTYPE, TCTYPE_VAL_USERTYPE(typeDef)); UNPROTECT(save); return td; } static TcType *listOf(TcType *type) { - TcTypeDefArgs *args = newTcTypeDefArgs(type, NULL); + TcUserTypeArgs *args = newTcUserTypeArgs(type, NULL); int save = PROTECT(args); - TcType *td = makeTypeDef("list", args); + TcType *td = makeUserType("list", args); UNPROTECT(save); return td; } @@ -281,7 +281,7 @@ static void test_id() { int save = PROTECT(result); TcType *res = analyze(result); PROTECT(res); - TcType *expected = makeTypeDef("bool", NULL); + TcType *expected = makeUserType("bool", NULL); PROTECT(expected); assert(compareTcTypes(res, expected)); UNPROTECT(save); @@ -297,11 +297,11 @@ static void test_either_1() { PROTECT(big); TcType *var = makeVar("#t"); PROTECT(var); - TcTypeDefArgs *args = newTcTypeDefArgs(var, NULL); + TcUserTypeArgs *args = newTcUserTypeArgs(var, NULL); PROTECT(args); - args = newTcTypeDefArgs(big, args); + args = newTcUserTypeArgs(big, args); PROTECT(args); - TcType *expected = makeTypeDef("either", args); + TcType *expected = makeUserType("either", args); PROTECT(expected); assert(compareTcTypes(res, expected)); UNPROTECT(save); From 6d3eeff38c203b4cea3a5a58244d6e92ce1396ca Mon Sep 17 00:00:00 2001 From: Bill Hails Date: Sat, 16 Mar 2024 16:03:32 +0000 Subject: [PATCH 24/33] fixed parser bug --- Makefile | 4 ++-- fn/bugs.fn | 32 ++++---------------------------- fn/listutils.fn | 2 -- fn/pythagoreanTriples.fn | 2 +- src/common.h | 6 ++++-- src/parser.y | 14 +++++++++----- src/tpmc_match.c | 1 + 7 files changed, 21 insertions(+), 40 deletions(-) diff --git a/Makefile b/Makefile index b7d99d7..b9723d3 100644 --- a/Makefile +++ b/Makefile @@ -7,9 +7,9 @@ TARGET=cekf # written to /var/lib/apport/coredump/ MODE_P=-pg MODE_O=-O2 -MODE_D=-g -DDEBUG_ANY +MODE_D=-g -CCMODE = $(MODE_O) +CCMODE = $(MODE_D) CC=cc -Wall -Wextra -Werror $(CCMODE) LAXCC=cc -Werror $(CCMODE) diff --git a/fn/bugs.fn b/fn/bugs.fn index 0e93bcf..c17cd9e 100644 --- a/fn/bugs.fn +++ b/fn/bugs.fn @@ -1,33 +1,9 @@ let - // foldl :: (a -> b -> b) -> b -> list(a) -> b - // ((#cn) -> (#ym) -> #hn [#ym]) -> (#ym) -> (list(#cn)) -> #ym - // (a -> b -> b ) -> b -> list(a) -> b - fn foldl { - (_, acc, []) { acc } - (func, acc, h @ t) { foldl(func, func(h, acc), t) } - } - - // foldr :: (a -> b -> b) -> b -> list(a) -> b - // ((#nn) -> (#xn) -> #xn) -> (#xn) -> (#mn) -> #xn - // (a -> b -> b ) -> b -> ??? -> b - fn foldr(func, acc, lst) { - foldl(func, acc, reverse(lst)) - } - - // reverse :: list(#t) -> list(#t) - // (list(#no)) -> list(#no) - fn reverse (lst) { - foldl(fn (elem, acc) { elem @ acc }, [], lst) - } - - // BUG concat list of strings prints as a list of char rather than a string - // BUT if we define reverse before foldl it all works. - // concat :: list(list(#t)) -> list(#t) - // (380) -> list(<#t/421>395) - fn concat(lst) { - foldr(fn (elem, acc) { elem @@ acc }, [], lst) + fn last { + ([a]) { a } + (_ @ t) { last(t) } } in - print(concat(["well", " ", "hi", " ", "there"])) + print(last(["well", " ", "hi", " ", "there"])) diff --git a/fn/listutils.fn b/fn/listutils.fn index 365f9fe..b27e2dd 100644 --- a/fn/listutils.fn +++ b/fn/listutils.fn @@ -56,7 +56,6 @@ let } } - // BUG concat list of strings prints as a list of char rather than a string fn concat(lst) { foldr(fn (elem, acc) { elem @@ acc }, [], lst) } @@ -105,7 +104,6 @@ let (_, _, _) { [] } } - // BUG replacing (a @ []) with ([a]) causes error fn last { (a @ []) { a } (_ @ t) { last(t) } diff --git a/fn/pythagoreanTriples.fn b/fn/pythagoreanTriples.fn index aa37497..192f49f 100644 --- a/fn/pythagoreanTriples.fn +++ b/fn/pythagoreanTriples.fn @@ -26,5 +26,5 @@ in { in print(triple); puts("\n"); - require( 50) // until + require( 200) // until } diff --git a/src/common.h b/src/common.h index bc3a352..7f69464 100644 --- a/src/common.h +++ b/src/common.h @@ -23,13 +23,15 @@ typedef uint32_t hash_t; +# define DEBUG_ANY + # ifdef DEBUG_ANY // #define DEBUG_STACK // #define DEBUG_STEP // if DEBUG_STEP is defined, this sleeps for 1 second between each machine step // #define DEBUG_SLOW_STEP // define this to cause a GC at every malloc (catches memory leaks early) -// # define DEBUG_STRESS_GC +# define DEBUG_STRESS_GC // #define DEBUG_LOG_GC // #define DEBUG_GC // #define DEBUG_TPMC_MATCH @@ -53,7 +55,7 @@ typedef uint32_t hash_t; // #define DEBUG_PRINT_GENERATOR // #define DEBUG_PRINT_COMPILER // define this to turn on additional safety checks for things that shouldn't but just possibly might happen -// # define SAFETY_CHECKS +# define SAFETY_CHECKS # endif # ifndef __GNUC__ diff --git a/src/parser.y b/src/parser.y index e1e4c5c..60718ea 100644 --- a/src/parser.y +++ b/src/parser.y @@ -62,6 +62,10 @@ static AstFunCall *newStringList(AstCharArray *str) { return res; } +static AstArg *newAstNilArg() { + return newAstArg(AST_ARG_TYPE_SYMBOL, AST_ARG_VAL_SYMBOL(nilSymbol())); +} + static AstUnpack *newStringUnpack(AstCharArray *str) { AstUnpack *res = newAstUnpack(nilSymbol(), NULL); for (int size = str->size; size > 0; size--) { @@ -352,7 +356,7 @@ fargs : %empty { $$ = NULL; } | farg ',' fargs { $$ = newAstArgList($1, $3); } ; -consfargs : farg { $$ = newAstUnpack(consSymbol(), newAstArgList($1, NULL)); } +consfargs : farg { $$ = newAstUnpack(consSymbol(), newAstArgList($1, newAstArgList(newAstNilArg(), NULL))); } | farg ',' consfargs { $$ = newAstUnpack(consSymbol(), newAstArgList($1, newAstArgList(newAstArg(AST_ARG_TYPE_UNPACK, AST_ARG_VAL_UNPACK($3)), NULL))); } ; @@ -362,7 +366,7 @@ farg : symbol { $$ = newAstArg(AST_ARG_TYPE_SYMBOL, AST_ARG_VAL_SYM | unpack { $$ = newAstArg(AST_ARG_TYPE_UNPACK, AST_ARG_VAL_UNPACK($1)); } | cons { $$ = newAstArg(AST_ARG_TYPE_UNPACK, AST_ARG_VAL_UNPACK($1)); } | named_farg { $$ = newAstArg(AST_ARG_TYPE_NAMED, AST_ARG_VAL_NAMED($1)); } - | '[' ']' { $$ = newAstArg(AST_ARG_TYPE_SYMBOL, AST_ARG_VAL_SYMBOL(nilSymbol())); } + | '[' ']' { $$ = newAstNilArg(); } | '[' consfargs ']' { $$ = newAstArg(AST_ARG_TYPE_UNPACK, AST_ARG_VAL_UNPACK($2)); } | env_type { $$ = newAstArg(AST_ARG_TYPE_ENV, AST_ARG_VAL_ENV($1)); } | number { $$ = newAstArg(AST_ARG_TYPE_NUMBER, AST_ARG_VAL_NUMBER($1)); } @@ -371,6 +375,9 @@ farg : symbol { $$ = newAstArg(AST_ARG_TYPE_SYMBOL, AST_ARG_VAL_SYM | WILDCARD { $$ = newAstArg(AST_ARG_TYPE_WILDCARD, AST_ARG_VAL_WILDCARD()); } ; +cons : farg CONS farg { $$ = newAstUnpack(consSymbol(), newAstArgList($1, newAstArgList($3, NULL))); } + ; + unpack : symbol '(' fargs ')' { $$ = newAstUnpack($1, $3); } ; @@ -384,9 +391,6 @@ str : STRING { $$ = newCharArray($1); } | str STRING { $$ = appendCharArray($1, $2); } ; -cons : farg CONS farg { $$ = newAstUnpack(consSymbol(), newAstArgList($1, newAstArgList($3, NULL))); } - ; - env_type : symbol ':' symbol { $$ = newAstEnvType($1, $3); } ; diff --git a/src/tpmc_match.c b/src/tpmc_match.c index f92eac3..fc8635c 100644 --- a/src/tpmc_match.c +++ b/src/tpmc_match.c @@ -262,6 +262,7 @@ static void populateSubPatternMatrixRowWithComponents(TpmcMatrix *matrix, TpmcPattern *pattern) { ENTER(populateSubPatternMatrixRowWithComponents); if (arity != pattern->pattern->val.constructor->components->size) { + printTpmcPattern(pattern, 0); cant_happen ("arity %d does not match constructor arity %d in populateSubPatternMatrixRowWithComponents", arity, pattern->pattern->val.constructor->components->size); From a07bc786ea4eac2f0b238321b2cdd275d50ffee4 Mon Sep 17 00:00:00 2001 From: Bill Hails Date: Thu, 28 Mar 2024 17:13:49 +0000 Subject: [PATCH 25/33] various simplifications * simpler lower-level matrix and array operations in tpmc_match * added documentation * unified error and debug output * improved code generation capabilities (array iteration etc.) * general clean-up --- Makefile | 2 +- docs/TODO.md | 4 + docs/V2.md | 13 +- docs/lambda-conversion.md | 98 +++++++++ fn/listutils.fn | 10 +- fn/pythagoreanTriples.fn | 2 +- src/anf_pp.c | 4 +- src/bigint.c | 2 +- src/common.h | 10 +- src/debug.c | 6 +- src/errors.c | 8 +- src/lambda_pp.c | 8 +- src/main.c | 3 + src/memory.c | 2 +- src/parser.y | 4 +- src/primitives.yaml | 1 + src/tpmc_compare.c | 2 + src/tpmc_logic.c | 23 ++- src/tpmc_match.c | 417 ++++++++++++++------------------------ src/tpmc_translate.c | 22 +- tools/makeAST.py | 89 +++++++- 21 files changed, 409 insertions(+), 321 deletions(-) diff --git a/Makefile b/Makefile index b9723d3..564b17b 100644 --- a/Makefile +++ b/Makefile @@ -54,7 +54,7 @@ EXTRA_DEP=$(patsubst obj/%,dep/%,$(patsubst %.o,%.d,$(EXTRA_OBJ))) PARSER_DEP=$(patsubst obj/%,dep/%,$(patsubst %.o,%.d,$(PARSER_OBJ))) ALL_OBJ=$(OBJ) $(EXTRA_OBJ) $(PARSER_OBJ) -ALL_DEP=$(DEP) $(EXTRA_DEP) $(TEST_DEP) $(PARSER_DEP) +ALL_DEP=$(DEP) $(EXTRA_DEP) $(TEST_DEP) $(PARSER_DEP) $(MAIN_DEP) TMP_H=generated/parser.h generated/lexer.h TMP_C=generated/parser.c generated/lexer.c diff --git a/docs/TODO.md b/docs/TODO.md index dae770d..f64b19b 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -5,6 +5,7 @@ * tuples - can use vec type to implement. * BUT - fn args are not tuples, that might interfere with currying. * tc has support for pairs and we might leverage those as a start, but flat vecs will be more efficient. + * specific syntax: `#(2, "hi")` might be better than just round braces. * unpacking function return values (tuples only) * `now()` expression returns current time in milliseconds. * macro support (see [MACROS](./MACROS.md) for initial thoughts). @@ -24,3 +25,6 @@ * command-line arguments for libraries etc. * fail on non-exhaustive pattern match (optional). * error function +* user definable infix operators + * with precedence and associativity +* curried binary operators `(2+)` etc. diff --git a/docs/V2.md b/docs/V2.md index 1cb6f47..9788fbc 100644 --- a/docs/V2.md +++ b/docs/V2.md @@ -138,7 +138,14 @@ I should probably explain that. Consider a primitive sequence like `2 + 3 * 4`. That will parse to `2 + (3 * 4)` and the AST will look like: -![AST](parse-tree.png) +```mermaid +flowchart TD +plus(+) +plus ---- two(2) +plus --- times(×) +times --- three(3) +times --- four(4) +``` There are various ways to print out that tree, for example for each (non-terminal) node, printing the left hand branch, then printing the @@ -584,8 +591,8 @@ In all other cases the called function can re-use the calling function's stack f ### Changes to V2 -Firstly we're going to need a new register to keep track of the stack, all the good letters are gone so I'm just going to call it `S`. -Our CEKF machine is now a CEKFS machine. +Firstly we're going to need a new register to keep track of the stack, all the good letters are gone so I'm just going to call it `(s)`. +Our `CEKF` machine is now a `CEKF(s)` machine. #### Variables diff --git a/docs/lambda-conversion.md b/docs/lambda-conversion.md index 7b65587..2824aaf 100644 --- a/docs/lambda-conversion.md +++ b/docs/lambda-conversion.md @@ -459,6 +459,104 @@ has a complete algorithm described and working that does exactly what I want! Plan now is to get that working as a Python prototype, then translate into C. +## Description of the TPMC Algorithm + +Explaining it to myself. + +### Step 1. Renaming + +All patterns in the arguments to a composite function are collected into a matrix +of patterns, and the components are renamed and labelled in a consistent way, +such thar the same variable position has the same name, for example in + +``` +fn map { + (_, nil) { nil } + (f, pair(h, t)) { pair(f(h), map(f, t)) } +} +``` + +The matrix is + +``` +(_, nil) +(f, pair(h, t)) +``` + +and after renaming and labelling that becomes + +``` +(p$0=_, p$1=nil) +(p$0=_, p$1=pair(p$1$0=_, p$1$1=_)) +``` + +An array of final states (the bodies of the individual functions) is also constructed + +``` +{ nil } +{ pair(p$0(p$1$0), map(p$0, p$1$1)) } +``` + +### Step 2. Generating the DFA + +The input to the `match` algorithm is that matrix of patterns M and the array of final states S. +The output of the `match` algorithm is the DFA for the matrix. + +`match` inspects the first (top) row of M. If all of the patterns in the row are +variables then it cannot fail to match any arguments. This invokes the "Variable Rule". +Otherwise at least one pattern in the top row is a constructor or constant. This situation +invokes the "Mixture Rule". + +#### The Variable Rule + +If there are no constructors or constants in the top row then the result is the first state in the array of final states. + +#### The Mixture Rule + +* select any column C whose first pattern is not a wildcard. +* construct an array N containing the patterns from any column whose first pattern is not a wildcard. +* construct a new matrix MN consisting of all the columns from M except that column. +* construct a new test state T. +* for each constructor K in N: + * let AK be the arity of K. + * let {i1 .. ii} be the indices of the patterns in N (both wildcards and equal constructors) that match that constructor. + * let {p1 .. pi} be the patterns at those indices. + * let L be the size of {p1 .. pi} + * construct a matrix MNC from MN by selecting rows {i1 .. ii} + * construct a matrix NC with AK columns and L rows + * for each pattern pj in {p1 .. pi} + * if pj is a constructor place a row of the constructor's AK arguments in row j of NC + * otherwise place a row of AK wildcards with appropriate names (p$1$1 etc.( in row j of NC + * construct a new matrix MNCNC by appending MN to MNC + * let SN be an array of S's states {i1 .. ii} + * call `match` on MNCNC and SN to get state F + * create an arc from T to F, labelling it with the constructor K +* if the list of constructors in N is exhaustive + * return T +* else if there are wildcards in N: + * let {w1 .. wi} be the indices of the wildcards in N + * construct a matrix MNF by selecting rows {w1 .. wn} + * construct a state array SF from S by selecting states {w1 .. wi} + * call match on MNF and SF resulting in a DFA F + * add an arc from T to F labelled with a wildcard + * return T +* else: + * add an arc from T to the error state E + * return T + +### Step 3. Optimize the DFA + +This just involves reference counting states and removing duplicates. +States with a reference count greater than one will become local functions. + +### Step 4. Generate Intermediate Code + +Again this is fairly straightforward, local procedures are created for those +states with multiple entry points, so track must be kept of free variables etc. +Otherwise a test state becomes a switch statement (in our case either a `MATCH` +for constructors or a `COND` for constants), an arc becomes a case in that statement, +and a final state is either the body of the state or a call to the local procedure. + And it's working! At least the python prototype [TPMC2.py](../prototyping/TPMC2.py). For sample inputs here's the output: ```scheme diff --git a/fn/listutils.fn b/fn/listutils.fn index b27e2dd..f9a94d5 100644 --- a/fn/listutils.fn +++ b/fn/listutils.fn @@ -39,8 +39,8 @@ let fn scanl (func, acc, lst) { let fn scan { - (accl, []) { accl } - (acc = acch @ acct, lsth @ lstt) { scan(func(lsth, acch) @ acc, lstt) } + (acc, []) { acc } + (acc = acc_h @ _, lst_h @ lst_t) { scan(func(lst_h, acc_h) @ acc, lst_t) } } in scan([acc], lst) } @@ -105,7 +105,7 @@ let } fn last { - (a @ []) { a } + ([a]) { a } (_ @ t) { last(t) } } @@ -135,7 +135,7 @@ let } fn range(low, high) { - if (low >= high) { [] } + if (low > high) { [] } else { low @ range(low + 1, high) } } @@ -182,5 +182,5 @@ let } in - print(concat(["well", " ", "hi", " ", "there"])); + print(concat(take(3, ["well", " ", "hi", " ", "there"]))); puts("\n") diff --git a/fn/pythagoreanTriples.fn b/fn/pythagoreanTriples.fn index 192f49f..8bddcf9 100644 --- a/fn/pythagoreanTriples.fn +++ b/fn/pythagoreanTriples.fn @@ -26,5 +26,5 @@ in { in print(triple); puts("\n"); - require( 200) // until + require( 20) // until } diff --git a/src/anf_pp.c b/src/anf_pp.c index 75642ae..17b7b28 100644 --- a/src/anf_pp.c +++ b/src/anf_pp.c @@ -215,7 +215,7 @@ void ppCexpCond(CexpCond *x) { void ppCexpIntCondCases(CexpIntCondCases *x) { while (x != NULL) { eprintf("("); - fprintBigInt(stderr, x->option); + fprintBigInt(errout, x->option); eprintf(" "); ppExp(x->body); eprintf(")"); @@ -351,7 +351,7 @@ void ppAexp(Aexp *x) { eprintf("nil"); break; case AEXP_TYPE_BIGINTEGER: - fprintBigInt(stderr, x->val.biginteger); + fprintBigInt(errout, x->val.biginteger); break; case AEXP_TYPE_LITTLEINTEGER: eprintf("%d", x->val.littleinteger); diff --git a/src/bigint.c b/src/bigint.c index db19d9b..1b64c59 100644 --- a/src/bigint.c +++ b/src/bigint.c @@ -1301,7 +1301,7 @@ void freeBigInt(BigInt *x) { void printBigInt(BigInt *x, int depth) { eprintf("%*s", depth * PAD_WIDTH, ""); - fprintBigInt(stderr, x); + fprintBigInt(errout, x); } void bigint_fprint(FILE *f, bigint * bi) { diff --git a/src/common.h b/src/common.h index 7f69464..d37ca15 100644 --- a/src/common.h +++ b/src/common.h @@ -18,6 +18,7 @@ * along with this program. If not, see . */ +# include # include # include @@ -34,9 +35,9 @@ typedef uint32_t hash_t; # define DEBUG_STRESS_GC // #define DEBUG_LOG_GC // #define DEBUG_GC -// #define DEBUG_TPMC_MATCH -// #define DEBUG_TPMC_TRANSLATE -// #define DEBUG_TPMC_LOGIC +# define DEBUG_TPMC_MATCH +// # define DEBUG_TPMC_TRANSLATE +# define DEBUG_TPMC_LOGIC // #define DEBUG_ANNOTATE // #define DEBUG_DESUGARING // #define DEBUG_HASHTABLE @@ -47,7 +48,7 @@ typedef uint32_t hash_t; // define this to make fatal errors dump core (if ulimit allows) # define DEBUG_DUMP_CORE // # define DEBUG_TC -// #define DEBUG_LAMBDA_CONVERT +// # define DEBUG_LAMBDA_CONVERT // #define DEBUG_LAMBDA_SUBSTITUTE // #define DEBUG_LEAK // #define DEBUG_ANF @@ -61,6 +62,7 @@ typedef uint32_t hash_t; # ifndef __GNUC__ # define __attribute__(x) # endif +# define errout stdout void cant_happen(const char *message, ...) __attribute__((noreturn, format(printf, 1, 2))); void can_happen(const char *message, ...) diff --git a/src/debug.c b/src/debug.c index fafad57..93fc128 100644 --- a/src/debug.c +++ b/src/debug.c @@ -49,7 +49,7 @@ void printContainedValue(Value x, int depth) { break; case VALUE_TYPE_BIGINT: printPad(depth); - fprintBigInt(stderr, x.val.b); + fprintBigInt(errout, x.val.b); break; case VALUE_TYPE_CHARACTER: printPad(depth); @@ -464,7 +464,7 @@ void dumpByteCode(ByteCodeArray *b) { if (bigint_flag) { bigint bi = readBigint(b, &i); eprintf(" "); - bigint_fprint(stderr, &bi); + bigint_fprint(errout, &bi); bigint_free(&bi); } else { int li = readInt(b, &i); @@ -546,7 +546,7 @@ void dumpByteCode(ByteCodeArray *b) { case BYTECODE_BIGINT:{ eprintf("BIGINT ["); bigint bi = readBigint(b, &i); - bigint_fprint(stderr, &bi); + bigint_fprint(errout, &bi); eprintf("]\n"); bigint_free(&bi); } diff --git a/src/errors.c b/src/errors.c index cd12c7a..0aa9c5f 100644 --- a/src/errors.c +++ b/src/errors.c @@ -28,12 +28,10 @@ static bool errors = false; -#define __OUT__ stderr - void cant_happen(const char *message, ...) { va_list args; va_start(args, message); - vfprintf(__OUT__, message, args); + vfprintf(errout, message, args); va_end(args); eprintf("\n"); #ifdef DEBUG_DUMP_CORE @@ -46,7 +44,7 @@ void cant_happen(const char *message, ...) { void can_happen(const char *message, ...) { va_list args; va_start(args, message); - vfprintf(__OUT__, message, args); + vfprintf(errout, message, args); va_end(args); eprintf("\n"); errors = true; @@ -55,7 +53,7 @@ void can_happen(const char *message, ...) { void eprintf(const char *message, ...) { va_list args; va_start(args, message); - vfprintf(__OUT__, message, args); + vfprintf(errout, message, args); va_end(args); } diff --git a/src/lambda_pp.c b/src/lambda_pp.c index 69fc607..244a4d3 100644 --- a/src/lambda_pp.c +++ b/src/lambda_pp.c @@ -110,7 +110,7 @@ void ppLamExp(LamExp *exp) { ppHashSymbol(exp->val.var); break; case LAMEXP_TYPE_BIGINTEGER: - fprintBigInt(stderr, exp->val.biginteger); + fprintBigInt(errout, exp->val.biginteger); break; case LAMEXP_TYPE_STDINT: eprintf("%d", exp->val.stdint); @@ -355,7 +355,7 @@ void ppLamIff(LamIff *iff) { static void _ppLamIntCondCases(LamIntCondCases *cases) { eprintf("("); - fprintBigInt(stderr, cases->constant); + fprintBigInt(errout, cases->constant); eprintf(" "); ppLamExp(cases->body); eprintf(")"); @@ -636,7 +636,7 @@ void ppLamIntList(LamIntList *list) { void ppLamConstruct(LamConstruct *construct) { eprintf("(construct "); ppHashSymbol(construct->name); - eprintf(" %d", construct->tag); + eprintf(" [%d]", construct->tag); _ppLamList(construct->args); eprintf(")"); } @@ -656,7 +656,7 @@ void ppLamConstant(LamConstant *constant) { void ppLamDeconstruct(LamDeconstruct *deconstruct) { eprintf("(deconstruct "); ppHashSymbol(deconstruct->name); - eprintf(" %d ", deconstruct->vec); + eprintf("[%d]", deconstruct->vec); ppLamExp(deconstruct->exp); eprintf(")"); } diff --git a/src/main.c b/src/main.c index aef3069..e664a96 100644 --- a/src/main.c +++ b/src/main.c @@ -42,6 +42,7 @@ #include "bigint.h" #include "tc_analyze.h" #include "tc_debug.h" +#include "tpmc_mermaid.h" int report_flag = 0; static int help_flag = 0; @@ -53,6 +54,7 @@ static void processArgs(int argc, char *argv[]) { static struct option long_options[] = { { "bigint", no_argument, &bigint_flag, 1 }, { "report", no_argument, &report_flag, 1 }, + { "tpmc-mermaid", no_argument, &tpmc_mermaid_flag, 1 }, { "help", no_argument, &help_flag, 1 }, { 0, 0, 0, 0 } }; @@ -68,6 +70,7 @@ static void processArgs(int argc, char *argv[]) { printf("%s", "--bigint use arbitrary precision integers\n" "--report report statistics\n" + "--tpmc-mermaid produce a mermaid graph of each TPMC state table\n" "--help this help\n"); exit(0); } diff --git a/src/memory.c b/src/memory.c index 2f08d04..af4292d 100644 --- a/src/memory.c +++ b/src/memory.c @@ -144,7 +144,7 @@ void replaceProtect(int i, Header *obj) { int protect(Header *obj) { #ifdef DEBUG_LOG_GC - fprintf(stderr, "PROTECT(%p:%s) -> %d (%d)\n", obj, + fprintf(errout, "PROTECT(%p:%s) -> %d (%d)\n", obj, (obj == NULL ? "NULL" : typeName(obj->type, obj)), protected->sp, protected->capacity); #endif diff --git a/src/parser.y b/src/parser.y index 60718ea..f6fac13 100644 --- a/src/parser.y +++ b/src/parser.y @@ -485,9 +485,9 @@ print : PRINT '(' expression ')' { $$ = newAstPrint($3); } %% void yyerror (yyscan_t *locp, PmModule *mod, char const *msg) { - fprintf(stderr, "%s\n", msg); + fprintf(errout, "%s\n", msg); if (mod && mod->bufStack) { - showModuleState(stderr, mod); + showModuleState(errout, mod); } abort(); } diff --git a/src/primitives.yaml b/src/primitives.yaml index 8581dc2..3151127 100644 --- a/src/primitives.yaml +++ b/src/primitives.yaml @@ -47,6 +47,7 @@ BigInt: cname: "BigInt *" printFn: "printBigInt" markFn: "markBigInt" + compareFn: "cmpBigInt" valued: true string: diff --git a/src/tpmc_compare.c b/src/tpmc_compare.c index 1d78f26..03558ee 100644 --- a/src/tpmc_compare.c +++ b/src/tpmc_compare.c @@ -18,6 +18,8 @@ * Term Pattern Matching Compiler logic */ +// TODO should be able to get rid of this now we auto-generate comparison functions + #include "tpmc_compare.h" #define PREAMBLE() do {\ diff --git a/src/tpmc_logic.c b/src/tpmc_logic.c index f6785ce..addbc67 100644 --- a/src/tpmc_logic.c +++ b/src/tpmc_logic.c @@ -19,6 +19,7 @@ */ #include +#include #include "common.h" #include "tpmc_logic.h" #include "tpmc_translate.h" @@ -30,6 +31,8 @@ #include "memory.h" #include "lambda_substitution.h" #include "lambda_pp.h" +#include "tpmc_mermaid.h" +#include "tpmc_pp.h" #ifdef DEBUG_TPMC_LOGIC # include "debugging_on.h" #else @@ -39,13 +42,16 @@ static TpmcPattern *convertPattern(AstArg *arg, LamContext *env); static TpmcVariableArray *createRootVariables(int nargs) { + ENTER(createRootVariables); TpmcVariableArray *rootVariables = newTpmcVariableArray(); int p = PROTECT(rootVariables); for (int i = 0; i < nargs; i++) { HashSymbol *s = genSym("p$"); + IFDEBUG(eprintf("%s", s->name)); pushTpmcVariableArray(rootVariables, s); } UNPROTECT(p); + LEAVE(createRootVariables); return rootVariables; } @@ -241,6 +247,7 @@ static void renameConstructorPattern(TpmcConstructorPattern *pattern, if (snprintf(buf, 512, "%s$%d", path->name, i) >= 511) { can_happen("maximum path depth exceeded"); } + DEBUG("renameConstructorPattern: %s", buf); HashSymbol *newPath = newSymbol(buf); renamePattern(components->entries[i], newPath); } @@ -362,7 +369,7 @@ static TpmcPattern *replaceComparisonPattern(TpmcPattern *pattern, return replaceConstructorPattern(pattern, seen); case TPMCPATTERNVALUE_TYPE_COMPARISON: cant_happen - ("encounterted comparison pattern during replaceComparisonPattern"); + ("encounterted nested comparison pattern during replaceComparisonPattern"); default: cant_happen("unrecognised pattern type in renamePattern"); } @@ -547,6 +554,7 @@ static LamVarList *arrayToVarList(TpmcVariableArray *array) { LamLam *tpmcConvert(int nargs, int nbodies, AstArgList **argLists, LamExp **actions, LamContext *env) { + system("clear"); TpmcVariableArray *rootVariables = createRootVariables(nargs); int save = PROTECT(rootVariables); TpmcMatchRuleArray *rules = @@ -557,12 +565,12 @@ LamLam *tpmcConvert(int nargs, int nbodies, AstArgList **argLists, replaceComparisonRules(input); renameRules(input); performRulesSubstitutions(input); - DEBUG("*** RULES ***"); - IFDEBUG(printTpmcMatchRules(input, 0)); + // DEBUG("*** RULES ***"); + // IFDEBUG(printTpmcMatchRules(input, 0)); TpmcMatrix *matrix = convertToMatrix(input); PROTECT(matrix); DEBUG("*** MATRIX ***"); - IFDEBUG(printTpmcMatrix(matrix, 0)); + IFDEBUG(ppTpmcMatrix(matrix)); TpmcStateArray *finalStates = extractFinalStates(input); PROTECT(finalStates); TpmcStateArray *knownStates = newTpmcStateArray("tpmcConvert"); @@ -574,11 +582,12 @@ LamLam *tpmcConvert(int nargs, int nbodies, AstArgList **argLists, PROTECT(errorState); TpmcState *dfa = tpmcMatch(matrix, finalStates, errorState, knownStates); PROTECT(dfa); - DEBUG("*** DFA ***"); - IFDEBUG(printTpmcState(dfa, 0)); + // DEBUG("*** DFA ***"); + // IFDEBUG(printTpmcState(dfa, 0)); + tpmcMermaid(dfa); LamExp *body = tpmcTranslate(dfa); PROTECT(body); - DEBUG("tpmcTranslate returned %p", body); + // DEBUG("tpmcTranslate returned %p", body); LamVarList *args = arrayToVarList(rootVariables); PROTECT(args); LamLam *res = newLamLam(rootVariables->size, args, body); diff --git a/src/tpmc_match.c b/src/tpmc_match.c index fc8635c..0a33532 100644 --- a/src/tpmc_match.c +++ b/src/tpmc_match.c @@ -24,6 +24,7 @@ #include "tpmc_match.h" #include "tpmc_compare.h" #include "tpmc_debug.h" +#include "tpmc_pp.h" #include "lambda_debug.h" #include "lambda_helper.h" #include "symbol.h" @@ -49,16 +50,14 @@ TpmcState *tpmcMakeState(TpmcStateValue *val) { // TPMCPATTERNVALUE_TYPE_INTEGER // TPMCPATTERNVALUE_TYPE_CONSTRUCTOR -static bool patternIsWildcard(TpmcMatrix *m, int x, int y) { - TpmcPatternValueType type = getTpmcMatrixIndex(m, x, y)->pattern->type; - DEBUG("patternIsWildcard x = %d, y = %d, type = %d", x, y, type); - return type == TPMCPATTERNVALUE_TYPE_WILDCARD; +static bool patternIsWildcard(TpmcPattern *pattern) { + bool res = pattern->pattern->type == TPMCPATTERNVALUE_TYPE_WILDCARD; + return res; } static bool noRemainingTests(TpmcMatrix *matrix) { - DEBUG("noRemainingTests %d", matrix->width); for (int x = 0; x < matrix->width; x++) { - if (!patternIsWildcard(matrix, x, 0)) { + if (!patternIsWildcard(getTpmcMatrixIndex(matrix, x, 0))) { return false; } } @@ -67,7 +66,7 @@ static bool noRemainingTests(TpmcMatrix *matrix) { static int findFirstConstructorColumn(TpmcMatrix *matrix) { for (int x = 0; x < matrix->width; x++) { - if (!patternIsWildcard(matrix, x, 0)) { + if (!patternIsWildcard(getTpmcMatrixIndex(matrix, x, 0))) { return x; } } @@ -75,7 +74,6 @@ static int findFirstConstructorColumn(TpmcMatrix *matrix) { } static TpmcState *makeEmptyTestState(HashSymbol *path) { - ENTER(makeEmptyTestState); TpmcArcArray *arcs = newTpmcArcArray(); int save = PROTECT(arcs); TpmcTestState *test = newTpmcTestState(path, arcs); @@ -84,37 +82,21 @@ static TpmcState *makeEmptyTestState(HashSymbol *path) { TPMCSTATEVALUE_VAL_TEST(test)); PROTECT(val); TpmcState *state = tpmcMakeState(val); -#ifdef DEBUG_TPMC_MATCH2 - eprintf("makeEmptyTestState returning: "); - printTpmcState(state, 0); - eprintf("\n"); -#endif UNPROTECT(save); - LEAVE(makeEmptyTestState); return state; } static bool patternMatches(TpmcPattern *constructor, TpmcPattern *pattern) { - ENTER(patternMatches); -#ifdef DEBUG_TPMC_MATCH2 - eprintf("patternMatches constructor: "); - printTpmcPattern(constructor, 0); - eprintf("\npatternMatches pattern: "); - printTpmcPattern(pattern, 0); - eprintf("\n"); -#endif bool isComparison = (constructor->pattern->type == TPMCPATTERNVALUE_TYPE_COMPARISON); switch (pattern->pattern->type) { case TPMCPATTERNVALUE_TYPE_VAR: cant_happen("patternMatches ennncountered var"); case TPMCPATTERNVALUE_TYPE_COMPARISON: - LEAVE(patternMatches); - return true; + return eqTpmcPattern(constructor, pattern); case TPMCPATTERNVALUE_TYPE_ASSIGNMENT: cant_happen("patternMatches encountered assignment"); case TPMCPATTERNVALUE_TYPE_WILDCARD: - LEAVE(patternMatches); return true; case TPMCPATTERNVALUE_TYPE_CHARACTER:{ bool res = isComparison @@ -122,7 +104,6 @@ static bool patternMatches(TpmcPattern *constructor, TpmcPattern *pattern) { TPMCPATTERNVALUE_TYPE_CHARACTER && constructor->pattern->val.character == pattern->pattern->val.character); - LEAVE(patternMatches); return res; } case TPMCPATTERNVALUE_TYPE_BIGINTEGER:{ @@ -131,7 +112,6 @@ static bool patternMatches(TpmcPattern *constructor, TpmcPattern *pattern) { TPMCPATTERNVALUE_TYPE_BIGINTEGER && cmpBigInt(constructor->pattern->val.biginteger, pattern->pattern->val.biginteger) == 0); - LEAVE(patternMatches); return res; } case TPMCPATTERNVALUE_TYPE_CONSTRUCTOR:{ @@ -142,7 +122,6 @@ static bool patternMatches(TpmcPattern *constructor, TpmcPattern *pattern) { // pointer equivalence works for hash symbols constructor->pattern->val.constructor->tag == pattern->pattern->val.constructor->tag) || isComparison; - LEAVE(patternMatches); return res; } default: @@ -151,66 +130,108 @@ static bool patternMatches(TpmcPattern *constructor, TpmcPattern *pattern) { } } -static bool patternIndexMatches(TpmcMatrix *matrix, int x, int y, int yy) { - if (y == yy) { -#ifdef DEBUG_TPMC_MATCH2 - eprintf("patternIndexMatches is true trivially\n"); -#endif - return true; +TpmcIntArray *findPatternsMatching(TpmcPattern *c, TpmcPatternArray *N) { + TpmcIntArray *res = newTpmcIntArray(); + int save = PROTECT(res); + int i = 0; + TpmcPattern *candidate; + while (iterateTpmcPatternArray(N, &i, &candidate, NULL)) { + if (patternMatches(c, candidate)) { + pushTpmcIntArray(res, i - 1); + } } - TpmcPattern *constructor = getTpmcMatrixIndex(matrix, x, y); - TpmcPattern *pattern = getTpmcMatrixIndex(matrix, x, yy); - return patternMatches(constructor, pattern); + UNPROTECT(save); + return res; } -TpmcIntArray *findPatternsMatching(TpmcMatrix *matrix, int x, int y) { - ENTER(findPatternsMatching); - TpmcIntArray *res = newTpmcIntArray(); +static TpmcPatternArray *extractColumnSubset(TpmcPatternArray *N, + TpmcIntArray *ys) { + TpmcPatternArray *res = newTpmcPatternArray("extractColumnSubset"); int save = PROTECT(res); - for (int yy = 0; yy < matrix->height; yy++) { - if (patternIndexMatches(matrix, x, y, yy)) { - pushTpmcIntArray(res, yy); - } + int i = 0; + int y; + while (iterateTpmcIntArray(ys, &i, &y, NULL)) { + pushTpmcPatternArray(res, N->entries[y]); } -#ifdef DEBUG_TPMC_MATCH2 - eprintf("findPatternsMatching %d %d returning: ", x, y); - printTpmcIntArray(res, 0); - eprintf("\n"); -#endif UNPROTECT(save); - LEAVE(findPatternsMatching); return res; } -static TpmcPatternArray *extractMatrixColumnSubset(TpmcMatrix *matrix, int x, - TpmcIntArray *ys) { - ENTER(extractMatrixColumnSubset); - TpmcPatternArray *res = newTpmcPatternArray("extractMatrixColumnSubset"); +static TpmcPatternArray *extractMatrixColumn(TpmcMatrix *matrix, int x) { + TpmcPatternArray *res = newTpmcPatternArray("extractMatrixColumn"); int save = PROTECT(res); - for (int i = 0; i < ys->size; ++i) { - int y = ys->entries[i]; + for (int y = 0; y < matrix->height; y++) { pushTpmcPatternArray(res, getTpmcMatrixIndex(matrix, x, y)); } -#ifdef DEBUG_TPMC_MATCH2 - eprintf("extractMatrixColumnSubset returning: "); - printTpmcPatternArray(res, 0); - eprintf("\n"); -#endif UNPROTECT(save); - LEAVE(extractMatrixColumnSubset); + return res; +} + +static TpmcMatrix *discardMatrixColumn(TpmcMatrix *matrix, int column) { + TpmcMatrix *res = newTpmcMatrix(matrix->width - 1, matrix->height); + int save = PROTECT(res); + for (int x = 0; x < matrix->width; x++) { + for (int y = 0; y < matrix->height; y++) { + if (x < column) { + setTpmcMatrixIndex(res, x, y, + getTpmcMatrixIndex(matrix, x, y)); + } else if (x > column) { + setTpmcMatrixIndex(res, x - 1, y, + getTpmcMatrixIndex(matrix, x, y)); + } else { + // no-op + } + } + } + UNPROTECT(save); + return res; +} + +static TpmcMatrix *extractMatrixRows(TpmcMatrix *matrix, + TpmcIntArray *indices) { + TpmcMatrix *res = newTpmcMatrix(matrix->width, indices->size); + int save = PROTECT(res); + int resy = 0; + int iy = 0; + int i = 0; + while (iterateTpmcIntArray(indices, &i, &iy, NULL)) { + for (int x = 0; x < res->width; ++x) { + setTpmcMatrixIndex(res, x, resy, + getTpmcMatrixIndex(matrix, x, iy)); + } + resy++; + } + UNPROTECT(save); + return res; +} + +static TpmcMatrix *appendMatrices(TpmcMatrix *prefix, TpmcMatrix *suffix) { + if (prefix->height != suffix->height) { + cant_happen + ("appendMatrices given matrices with different heights, %d vs %d", + prefix->height, suffix->height); + } + TpmcMatrix *res = + newTpmcMatrix(prefix->width + suffix->width, prefix->height); + int save = PROTECT(res); + for (int x = 0; x < res->width; ++x) { + for (int y = 0; y < res->height; ++y) { + if (x >= prefix->width) { + setTpmcMatrixIndex(res, x, y, + getTpmcMatrixIndex(suffix, + x - prefix->width, y)); + } else { + setTpmcMatrixIndex(res, x, y, + getTpmcMatrixIndex(prefix, x, y)); + } + } + } + UNPROTECT(save); return res; } static TpmcStateArray *extractStateArraySubset(TpmcStateArray *all, TpmcIntArray *indices) { - ENTER(extractStateArraySubset); -#ifdef DEBUG_TPMC_MATCH2 - eprintf("extractStateArraySubset all: "); - printTpmcStateArray(all, 0); - eprintf("\nextractStateArraySubset indices: "); - printTpmcIntArray(indices, 0); - eprintf("\n"); -#endif TpmcStateArray *res = newTpmcStateArray("extractStateArraySubset"); int save = PROTECT(res); for (int i = 0; i < indices->size; ++i) { @@ -218,7 +239,6 @@ static TpmcStateArray *extractStateArraySubset(TpmcStateArray *all, pushTpmcStateArray(res, all->entries[j]); } UNPROTECT(save); - LEAVE(extractStateArraySubset); return res; } @@ -226,8 +246,6 @@ static int determineArity(TpmcPattern *pattern) { if (pattern->pattern->type == TPMCPATTERNVALUE_TYPE_CONSTRUCTOR) { LamTypeConstructorInfo *info = pattern->pattern->val.constructor->info; - DEBUG("'%s' has arity %d", - pattern->pattern->val.constructor->tag->name, info->arity); return info->arity; } else { return 0; @@ -237,7 +255,6 @@ static int determineArity(TpmcPattern *pattern) { static void populateSubPatternMatrixRowWithWildcards(TpmcMatrix *matrix, int y, int arity, TpmcPattern *pattern) { - ENTER(populateSubPatternMatrixRowWithWildcards); // FIXME safeMalloc this from strlen + some n char buf[512]; for (int i = 0; i < arity; i++) { @@ -254,15 +271,13 @@ static void populateSubPatternMatrixRowWithWildcards(TpmcMatrix *matrix, getTpmcMatrixIndex(matrix, i, y)->path = path; UNPROTECT(save); } - LEAVE(populateSubPatternMatrixRowWithWildcards); } static void populateSubPatternMatrixRowWithComponents(TpmcMatrix *matrix, int y, int arity, TpmcPattern *pattern) { - ENTER(populateSubPatternMatrixRowWithComponents); if (arity != pattern->pattern->val.constructor->components->size) { - printTpmcPattern(pattern, 0); + ppTpmcPattern(pattern); cant_happen ("arity %d does not match constructor arity %d in populateSubPatternMatrixRowWithComponents", arity, pattern->pattern->val.constructor->components->size); @@ -272,22 +287,20 @@ static void populateSubPatternMatrixRowWithComponents(TpmcMatrix *matrix, pattern->pattern->val.constructor->components->entries[i]; setTpmcMatrixIndex(matrix, i, y, entry); } - LEAVE(populateSubPatternMatrixRowWithComponents); } -static void populateSubPatternMatrix(TpmcMatrix *matrix, - TpmcPatternArray *patterns, int arity) { - ENTER(populateSubPatternMatrix); +static TpmcMatrix *makeSubPatternMatrix(TpmcPatternArray *patterns, int arity) { + TpmcMatrix *matrix = newTpmcMatrix(arity, patterns->size); if (arity == 0) { - LEAVE(populateSubPatternMatrix); - return; + return matrix; } + int save = PROTECT(matrix); for (int i = 0; i < patterns->size; ++i) { TpmcPattern *pattern = patterns->entries[i]; switch (pattern->pattern->type) { case TPMCPATTERNVALUE_TYPE_VAR: cant_happen - ("encountered pattern type var during populateSubPatternMatrix"); + ("encountered pattern type var during makeSubPatternMatrix"); case TPMCPATTERNVALUE_TYPE_COMPARISON: case TPMCPATTERNVALUE_TYPE_WILDCARD: populateSubPatternMatrixRowWithWildcards(matrix, i, arity, @@ -299,64 +312,24 @@ static void populateSubPatternMatrix(TpmcMatrix *matrix, break; case TPMCPATTERNVALUE_TYPE_ASSIGNMENT: cant_happen - ("encountered pattern type assignment during populateSubPatternMatrix"); + ("encountered pattern type assignment during makeSubPatternMatrix"); case TPMCPATTERNVALUE_TYPE_CHARACTER: cant_happen - ("encountered pattern type char during populateSubPatternMatrix"); + ("encountered pattern type char during makeSubPatternMatrix"); case TPMCPATTERNVALUE_TYPE_BIGINTEGER: cant_happen - ("encountered pattern type int during populateSubPatternMatrix"); + ("encountered pattern type int during makeSubPatternMatrix"); default: cant_happen - ("unrecognised pattern type %d during populateSubPatternMatrix", + ("unrecognised pattern type %d during makeSubPatternMatrix", pattern->pattern->type); } } - LEAVE(populateSubPatternMatrix); -} - -static void copyMatrixExceptColAndOnlyRows(int col, TpmcIntArray *ys, - TpmcMatrix *from, TpmcMatrix *to) { - ENTER(copyMatrixExceptColAndOnlyRows); - DEBUG("copyMatrixExceptColAndOnlyRows col : %d", col); -#ifdef DEBUG_TPMC_MATCH2 - eprintf("copyMatrixExceptColAndOnlyRows rows: "); - printTpmcIntArray(ys, 0); - eprintf("\n"); - DEBUG("copyMatrixExceptColAndOnlyRows from: %d * %d to: %d * %d", - from->width, from->height, to->width, to->height); -#endif - int tx = 0; - for (int x = 0; x < from->width; x++) { - if (x != col) { - for (int iy = 0; iy < ys->size; ++iy) { - int y = ys->entries[iy]; - DEBUG("copyMatrixExceptCol(%d), to[%d][%d] <= from[%d][%d]", - col, tx, iy, x, y); - setTpmcMatrixIndex(to, tx, iy, - getTpmcMatrixIndex(from, x, y)); - } - tx++; - } - } - LEAVE(copyMatrixExceptColAndOnlyRows); -} - -static void copyMatrixWithOffset(int offset, TpmcMatrix *from, TpmcMatrix *to) { - ENTER(copyMatrixWithOffset); - for (int x = 0; x < from->width; x++) { - for (int y = 0; y < from->height; ++y) { - DEBUG("copyMatrixWithOffset(%d), to[%d][%d] <= from[%d][%d]", - offset, x + offset, y, x, y); - setTpmcMatrixIndex(to, x + offset, y, - getTpmcMatrixIndex(from, x, y)); - } - } - LEAVE(copyMatrixWithOffset); + UNPROTECT(save); + return matrix; } static TpmcPattern *replaceComponentsWithWildcards(TpmcPattern *pattern) { - ENTER(replaceComponentsWithWildcards); if (pattern->pattern->type == TPMCPATTERNVALUE_TYPE_CONSTRUCTOR) { TpmcConstructorPattern *constructor = pattern->pattern->val.constructor; @@ -387,23 +360,19 @@ static TpmcPattern *replaceComponentsWithWildcards(TpmcPattern *pattern) { TpmcPattern *replacement = newTpmcPattern(patternValue); replacement->path = pattern->path; UNPROTECT(save); - LEAVE(replaceComponentsWithWildcards); return replacement; } } - LEAVE(replaceComponentsWithWildcards); return pattern; } static TpmcIntArray *makeTpmcIntArray(int size, int initialValue) { - ENTER(makeTpmcIntArray); TpmcIntArray *res = newTpmcIntArray(); int save = PROTECT(res); for (int i = 0; i < size; ++i) { pushTpmcIntArray(res, initialValue); } UNPROTECT(save); - LEAVE(makeTpmcIntArray); return res; } @@ -455,7 +424,6 @@ static bool constructorsAreExhaustive(TpmcState *state) { } static TpmcPattern *makeNamedWildcardPattern(HashSymbol *path) { - ENTER(makeNamedWildcardPattern); TpmcPatternValue *wc = newTpmcPatternValue(TPMCPATTERNVALUE_TYPE_WILDCARD, TPMCPATTERNVALUE_VAL_WILDCARD ()); @@ -463,7 +431,6 @@ static TpmcPattern *makeNamedWildcardPattern(HashSymbol *path) { TpmcPattern *pattern = newTpmcPattern(wc); pattern->path = path; UNPROTECT(save); - LEAVE(makeNamedWildcardPattern); return pattern; } @@ -471,31 +438,25 @@ static TpmcState *deduplicateState(TpmcState *state, TpmcStateArray *knownStates) { for (int i = 0; i < knownStates->size; i++) { if (tpmcStateEq(state, knownStates->entries[i])) { - DEBUG("deduplicateState found dup"); validateLastAlloc(); return knownStates->entries[i]; } } - DEBUG("deduplicateState adding new"); pushTpmcStateArray(knownStates, state); - DEBUG("deduplicateState added new"); return state; } static void collectPathsBoundByConstructor(TpmcPatternArray *components, TpmcVariableTable *boundVariables) { - ENTER(collectPathsBoundByConstructor); for (int i = 0; i < components->size; ++i) { TpmcPattern *pattern = components->entries[i]; setTpmcVariableTable(boundVariables, pattern->path); } - LEAVE(collectPathsBoundByConstructor); } static void collectPathsBoundByPattern(TpmcPattern *pattern, TpmcVariableTable *boundVariables) { - ENTER(collecPathsBoundByPattern); // FIXME is this correct? setTpmcVariableTable(boundVariables, pattern->path); switch (pattern->pattern->type) { @@ -521,22 +482,19 @@ static void collectPathsBoundByPattern(TpmcPattern *pattern, cant_happen("unrecognised type %d in collectPathsBoundByPattern", pattern->pattern->type); } - LEAVE("collecPathsBoundByPattern"); } static TpmcVariableTable *variablesBoundByPattern(TpmcPattern *pattern) { - ENTER(variablesBoundByPattern); TpmcVariableTable *boundVariables = newTpmcVariableTable(); int save = PROTECT(boundVariables); collectPathsBoundByPattern(pattern, boundVariables); UNPROTECT(save); - LEAVE(variablesBoundByPattern); return boundVariables; } static TpmcVariableTable *getTestStatesFreeVariables(TpmcTestState *testState) { - // The free variables of a test state is the union of the free variables of the outgoing arcs, plus the test variable. - ENTER(getTestStatesFreeVariables); + // The free variables of a test state is the union of the free variables + // of the outgoing arcs, plus the test variable. TpmcVariableTable *freeVariables = newTpmcVariableTable(); int save = PROTECT(freeVariables); setTpmcVariableTable(freeVariables, testState->path); @@ -554,12 +512,10 @@ static TpmcVariableTable *getTestStatesFreeVariables(TpmcTestState *testState) { } } UNPROTECT(save); - LEAVE(getTestStatesFreeVariables); return freeVariables; } static TpmcVariableTable *getStatesFreeVariables(TpmcState *state) { - ENTER(getStatesFreeVariables); if (state->freeVariables == NULL) { switch (state->state->type) { case TPMCSTATEVALUE_TYPE_TEST: @@ -578,12 +534,10 @@ static TpmcVariableTable *getStatesFreeVariables(TpmcState *state) { state->state->type); } } - LEAVE(getStatesFreeVariables); return state->freeVariables; } static TpmcArc *makeTpmcArc(TpmcState *state, TpmcPattern *pattern) { - ENTER(makeTpmcArc); TpmcArc *arc = newTpmcArc(state, pattern); int save = PROTECT(arc); // the free variables of an arc are the free variables of its state minus the variables bound in the pattern @@ -595,108 +549,59 @@ static TpmcArc *makeTpmcArc(TpmcState *state, TpmcPattern *pattern) { HashSymbol *key; while ((key = iterateTpmcVariableTable(statesFreeVariables, &i)) != NULL) { if (!getTpmcVariableTable(boundVariables, key)) { - DEBUG("makeTpmcArc adding free variable %s", key->name); setTpmcVariableTable(arc->freeVariables, key); } } state->refcount++; - DEBUG("makeTpmcArc creating arc to state with refcount %d", - state->refcount); - IFDEBUG(printTpmcState(state, 0)); UNPROTECT(save); - LEAVE(makeTpmcArc); return arc; } -#ifdef DEBUG_TPMC_MATCH -void ppPattern(TpmcPattern *pattern) { - eprintf("%s == ", pattern->path->name); - switch (pattern->pattern->type) { - case TPMCPATTERNVALUE_TYPE_COMPARISON:{ - TpmcComparisonPattern *c = pattern->pattern->val.comparison; - eprintf("(%s == %s)", c->previous->path->name, - c->current->path->name); - break; - } - case TPMCPATTERNVALUE_TYPE_WILDCARD: - eprintf("_"); - break; - case TPMCPATTERNVALUE_TYPE_CHARACTER: - eprintf("'%c'", pattern->pattern->val.character); - break; - case TPMCPATTERNVALUE_TYPE_BIGINTEGER: - fprintBigInt(stderr, pattern->pattern->val.biginteger); - break; - case TPMCPATTERNVALUE_TYPE_CONSTRUCTOR:{ - TpmcConstructorPattern *c = pattern->pattern->val.constructor; - eprintf("%s(", c->tag->name); - for (int i = 0; i < c->components->size; ++i) { - ppPattern(c->components->entries[i]); - if (i + 1 < c->components->size) { - eprintf(", "); - } - } - eprintf(")"); - break; - } - default: - cant_happen("ppPattern encountered unexpected type"); - } -} - -# define PPPATTERN(p) ppPattern(p); eprintf("\n") -#else -# define PPPATTERN(p) -#endif - -static TpmcState *mixture(TpmcMatrix *matrix, TpmcStateArray *finalStates, +static TpmcState *mixture(TpmcMatrix *M, TpmcStateArray *finalStates, TpmcState *errorState, TpmcStateArray *knownStates) { ENTER(mixture); - // there is some column whose topmost pattern is a constructor - int x = findFirstConstructorColumn(matrix); - // The goal is to build a test state with the variable v and some outgoing arcs (one for each constructor and possibly a default arc). - TpmcState *state = - makeEmptyTestState(getTpmcMatrixIndex(matrix, x, 0)->path); - int save = PROTECT(state); + // there is some column N whose topmost pattern is a constructor + int index = findFirstConstructorColumn(M); + DEBUG("mixture found constructor in column %d of %dx%d", index, M->width, M->height); + TpmcPatternArray *N = extractMatrixColumn(M, index); + int save = PROTECT(N); + DEBUGN("mixture extracted column %d: ", index); + IFDEBUGN(ppTpmcPatternArray(N)); + TpmcMatrix *MN = discardMatrixColumn(M, index); + PROTECT(MN); + // The goal is to build a test state with the variable v and some outgoing arcs + // (one for each constructor and possibly a default arc). + TpmcState *state = makeEmptyTestState(N->entries[0]->path); + PROTECT(state); // For each constructor c in the selected column, its arc is defined as follows: - for (int y = 0; y < matrix->height; y++) { - DEBUG("mixture examining[%d][%d]", x, y); - PPPATTERN(getTpmcMatrixIndex(matrix, x, y)); - if (!patternIsWildcard(matrix, x, y)) { - DEBUG("mixture pattern is not wildcard"); - TpmcPattern *c = getTpmcMatrixIndex(matrix, x, y); - // Let {i1 , ... , ij} be the row-indices of the patterns in the column that match c. - TpmcIntArray *matchingIndices = - findPatternsMatching(matrix, x, y); - validateLastAlloc(); + for (int row = 0; row < N->size; row++) { + TpmcPattern *c = N->entries[row]; + if (!patternIsWildcard(c)) { + DEBUGN("mixture considering pattern on row %d ", row); + IFDEBUGN(ppTpmcPattern(c)); + // Let {i1 , ... , ij} be the row-indices of the patterns in N that match c. + TpmcIntArray *matchingIndices = findPatternsMatching(c, N); int save2 = PROTECT(matchingIndices); // Let {pat1 , ... , patj} be the patterns in the column corresponding to the indices computed above, TpmcPatternArray *matchingPatterns = - extractMatrixColumnSubset(matrix, x, matchingIndices); + extractColumnSubset(N, matchingIndices); PROTECT(matchingPatterns); // let n be the arity of the constructor c int arity = determineArity(c); - // ... a pattern matrix with n columns and j rows (create ahead of time) - DEBUG("mixture - creating sub-pattern matrix %d * %d", arity, - matchingPatterns->size); - TpmcMatrix *subPatternMatrix = newTpmcMatrix(arity, matchingPatterns->size); // could be zero-width - PROTECT(subPatternMatrix); + DEBUG("arity %d\n", arity); // For each pati, its n sub-patterns are extracted; // if pati is a wildcard, n wildcards are produced instead, each tagged with the right path variable. - populateSubPatternMatrix(subPatternMatrix, matchingPatterns, - arity); - // This matrix is then appended to the result of selecting, from each column in the rest of the - // original matrix, those rows whose indices are in {i1 , ... , ij}. - TpmcMatrix *newMatrix = newTpmcMatrix(matrix->width + arity - 1, - matchingPatterns->size); - DEBUG("mixture - created newMatrix %d * %d", newMatrix->width, - newMatrix->height); + TpmcMatrix *subPatternMatrix = + makeSubPatternMatrix(matchingPatterns, arity); + PROTECT(subPatternMatrix); + // This matrix is then appended to the result of selecting, from each column in MN, + // those rows whose indices are in {i1 , ... , ij}. + TpmcMatrix *prefixMatrix = extractMatrixRows(MN, matchingIndices); + PROTECT(prefixMatrix); + TpmcMatrix *newMatrix = + appendMatrices(prefixMatrix, subPatternMatrix); PROTECT(newMatrix); - copyMatrixExceptColAndOnlyRows(x, matchingIndices, matrix, - newMatrix); - copyMatrixWithOffset(matrix->width - 1, subPatternMatrix, - newMatrix); // Finally the indices are used to select the corresponding final states that go with these rows. TpmcStateArray *newFinalStates = extractStateArraySubset(finalStates, matchingIndices); @@ -706,6 +611,7 @@ static TpmcState *mixture(TpmcMatrix *matrix, TpmcStateArray *finalStates, TpmcPattern *cPrime = replaceComponentsWithWildcards(c); PROTECT(cPrime); // and state is the result of recursively applying match to the new matrix and the new sequence of final states + DEBUG("mixture calling match for normal case, column %d row %d of %dx%d", index, row, M->width, M->height); TpmcState *newState = tpmcMatch(newMatrix, newFinalStates, errorState, knownStates); PROTECT(newState); @@ -715,6 +621,8 @@ static TpmcState *mixture(TpmcMatrix *matrix, TpmcStateArray *finalStates, arc->state->refcount--; validateLastAlloc(); } else { + DEBUGN("mixture constructed new arc: "); + IFDEBUGN(ppTpmcArc(arc)); pushTpmcArcArray(state->state->val.test->arcs, arc); } UNPROTECT(save2); @@ -725,7 +633,6 @@ static TpmcState *mixture(TpmcMatrix *matrix, TpmcStateArray *finalStates, if (constructorsAreExhaustive(state)) { TpmcState *res = deduplicateState(state, knownStates); UNPROTECT(save); - DEBUG("mixture - constructors are exhaustive"); LEAVE(mixture); return res; } @@ -733,47 +640,46 @@ static TpmcState *mixture(TpmcMatrix *matrix, TpmcStateArray *finalStates, // If there are any wildcard patterns in the selected column TpmcIntArray *wcIndices = newTpmcIntArray(); PROTECT(wcIndices); - for (int y = 0; y < matrix->height; y++) { - if (patternIsWildcard(matrix, x, y)) { - pushTpmcIntArray(wcIndices, y); + int row = 0; + TpmcPattern *candidate; + while (iterateTpmcPatternArray(N, &row, &candidate, NULL)) { + if (patternIsWildcard(candidate)) { + pushTpmcIntArray(wcIndices, row - 1); } } - if (wcIndices->size > 0) { + if (countTpmcIntArray(wcIndices) > 0) { // then their rows are selected from the rest of the matrix and the final states - TpmcMatrix *wcMatrix = - newTpmcMatrix(matrix->width - 1, wcIndices->size); + TpmcMatrix *wcMatrix = extractMatrixRows(MN, wcIndices); PROTECT(wcMatrix); - copyMatrixExceptColAndOnlyRows(x, wcIndices, matrix, wcMatrix); TpmcStateArray *wcFinalStates = extractStateArraySubset(finalStates, wcIndices); PROTECT(wcFinalStates); // and the state is the result of applying match to the new matrix and states + DEBUG("mixture calling match for error case"); TpmcState *wcState = tpmcMatch(wcMatrix, wcFinalStates, errorState, knownStates); PROTECT(wcState); TpmcPattern *wcPattern = - makeNamedWildcardPattern(getTpmcMatrixIndex(matrix, x, 0)->path); + makeNamedWildcardPattern(N->entries[0]->path); PROTECT(wcPattern); TpmcArc *wcArc = makeTpmcArc(wcState, wcPattern); PROTECT(wcArc); pushTpmcArcArray(state->state->val.test->arcs, wcArc); TpmcState *res = deduplicateState(state, knownStates); UNPROTECT(save); - DEBUG("mixture - wildcards supply default"); LEAVE(mixture); return res; } else { validateLastAlloc(); // Otherwise, the error state is used after its reference count has been incremented TpmcPattern *errorPattern = - makeNamedWildcardPattern(getTpmcMatrixIndex(matrix, x, 0)->path); + makeNamedWildcardPattern(N->entries[0]->path); PROTECT(errorPattern); TpmcArc *errorArc = makeTpmcArc(errorState, errorPattern); PROTECT(errorArc); pushTpmcArcArray(state->state->val.test->arcs, errorArc); TpmcState *res = deduplicateState(state, knownStates); UNPROTECT(save); - DEBUG("mixture - error state supplies default"); LEAVE(mixture); return res; } @@ -781,30 +687,21 @@ static TpmcState *mixture(TpmcMatrix *matrix, TpmcStateArray *finalStates, TpmcState *tpmcMatch(TpmcMatrix *matrix, TpmcStateArray *finalStates, TpmcState *errorState, TpmcStateArray *knownStates) { - ENTER(tpmcMatch); + ENTER(match); + IFDEBUG(ppTpmcMatrix(matrix)); + IFDEBUG(ppTpmcStateArray(finalStates)); if (matrix->height == 0) { cant_happen("zero-height matrix passed to match"); } TpmcState *res = NULL; -#ifdef DEBUG_TPMC_MATCH2 - eprintf("tpmcMatch: matrix: "); - printTpmcMatrix(matrix, 0); - eprintf("\ntpmcMatch: finalStates: "); - printTpmcStateArray(finalStates, 0); - eprintf("\n"); -#endif if (noRemainingTests(matrix)) { - DEBUG("variable rule applies"); + DEBUG("match: variable rule applies"); res = finalStates->entries[0]; } else { - DEBUG("mixture rule applies"); + DEBUG("match: mixture rule applies"); res = mixture(matrix, finalStates, errorState, knownStates); } - LEAVE(tpmcMatch); -#ifdef DEBUG_TPMC_MATCH2 - eprintf("tpmcMatch returning: "); - printTpmcState(res, 0); - eprintf("\n"); -#endif + IFDEBUG(ppTpmcState(res)); + LEAVE(match); return res; } diff --git a/src/tpmc_translate.c b/src/tpmc_translate.c index 9eccdae..c2e27e7 100644 --- a/src/tpmc_translate.c +++ b/src/tpmc_translate.c @@ -27,7 +27,7 @@ #include "common.h" #ifdef DEBUG_TPMC_TRANSLATE -# include "debug_tpmc.h" +# include "tpmc_debug.h" # include "debugging_on.h" #else # include "debugging_off.h" @@ -577,26 +577,6 @@ static LamCharCondCases *translateConstantCharArcList(TpmcArcList *arcList, return res; } -#ifdef DEBUG_TPMC_TRANSLATE -static int arcListLength(TpmcArcList *list) { - int i = 0; - while (list != NULL) { - list = list->next; - i++; - } - return i; -} - -static int intListLength(LamIntList *list) { - int i = 0; - while (list != NULL) { - list = list->next; - i++; - } - return i; -} -#endif - static LamMatchList *translateConstructorArcList(TpmcArcList *arcList, LamExp *testVar, LamIntList *unexhaustedIndices, diff --git a/tools/makeAST.py b/tools/makeAST.py index ce648c3..a7d9d05 100644 --- a/tools/makeAST.py +++ b/tools/makeAST.py @@ -1080,6 +1080,93 @@ def printMarkField(self, field, depth, prefix=''): pad(depth) print("mark{myName}(x->{prefix}{field}); // SimpleArray..printMarkField".format(field=field, myName=self.getName(), prefix=prefix)) + def getIterator1DDeclaration(self, catalog): + myName = self.getName() + myType = self.getTypeDeclaration() + myContainedType = self.entries.getTypeDeclaration(catalog) + return f'bool iterate{myName}({myType} table, int *i, {myContainedType} *res, bool *more)' + + def getIterator2DDeclaration(self, catalog): + myName = self.getName() + myType = self.getTypeDeclaration() + myContainedType = self.entries.getTypeDeclaration(catalog) + return f'bool iterate{myName}({myType} table, int *x, int *y, {myContainedType} *res, bool *more_x, bool *more_y)' + + def printIteratorDeclaration(self, catalog): + if self.dimension == 2: + self.printIterator2DDeclaration(catalog); + else: + self.printIterator1DDeclaration(catalog) + + def printIterator1DDeclaration(self, catalog): + decl = self.getIterator1DDeclaration(catalog) + print(f'{decl}; // SimpleArray.printIterator1DDeclaration') + + def printIterator2DDeclaration(self, catalog): + decl = self.getIterator2DDeclaration(catalog) + print(f'{decl}; // SimpleArray.printIterator2DDeclaration') + + def printIteratorFunction(self, catalog): + if self.dimension == 2: + self.printIterator2DFunction(catalog) + else: + self.printIterator1DFunction(catalog) + + def printIterator1DFunction(self, catalog): + decl = self.getIterator1DDeclaration(catalog) + print(f'{decl} {{ // SimpleArray.printIterator1DFunction') + print(' if (*i < 0 || *i >= table->size) {') + print(' if (more != NULL) {') + print(' *more = false;') + print(' }') + print(' return false;') + print(' } else {') + print(' if (more != NULL) {') + print(' *more = (*i + 1 < table->size);') + print(' }') + print(' if (res != NULL) {') + print(' *res = table->entries[*i];') + print(' }') + print(' *i = *i + 1;') + print(' return true;') + print(' }') + print('} // SimpleArray.printIteratorFunction') + print('') + + def printIterator2DFunction(self, catalog): + decl = self.getIterator2DDeclaration(catalog) + print(f'{decl} {{ // SimpleArray.printIterator2DFunction') + print(' if (*x < 0 || *x >= table->width) {') + print(' if (more_x != NULL) {') + print(' *more_x = false;') + print(' }') + print(' return false;') + print(' } else if (*y < 0 || *y >= table->height) {') + print(' if (more_y != NULL) {') + print(' *more_y = false;') + print(' }') + print(' return false;') + print(' } else {') + print(' if (more_x != NULL) {') + print(' *more_x = (*x + 1 < table->width);') + print(' }') + print(' if (more_y != NULL) {') + print(' *more_y = (*y + 1 < table->height);') + print(' }') + print(' if (res != NULL) {') + print(' *res = table->entries[*x * table->width + *y];') + print(' }') + print(' if (*x + 1 == table->width) {') + print(' *x = 0;') + print(' *y = *y + 1;') + print(' } else {') + print(' *x = *x + 1;') + print(' }') + print(' return true;') + print(' }') + print('} // SimpleArray.printIteratorFunction') + print('') + def isArray(self): return True @@ -1722,7 +1809,7 @@ def printCompareField(self, field, depth, prefix=''): if self.compareFn is None: print(f"if (a->{prefix}{field} != b->{prefix}{field}) return false; // Primitive.printCompareField") else: - print(f"if (!{self.compareFn}(a->{prefix}{field}, b->{prefix}{field})) return false; // Primitive.printCompareField") + print(f"if ({self.compareFn}(a->{prefix}{field}, b->{prefix}{field})) return false; // Primitive.printCompareField") def printPrintHashField(self, depth): pad(depth) From b7c98da431894d7e21adf304e010c77362dcba90 Mon Sep 17 00:00:00 2001 From: Bill Hails Date: Thu, 28 Mar 2024 17:18:28 +0000 Subject: [PATCH 26/33] overlooked additions --- docs/TPMC.drawio | 861 +++++++++++++++++++++++++++++++++++++++++++++ fn/derivative.fn | 20 ++ fn/derivative2.fn | 73 ++++ src/tpmc_mermaid.c | 183 ++++++++++ src/tpmc_mermaid.h | 26 ++ src/tpmc_pp.c | 226 ++++++++++++ src/tpmc_pp.h | 41 +++ 7 files changed, 1430 insertions(+) create mode 100644 docs/TPMC.drawio create mode 100644 fn/derivative.fn create mode 100644 fn/derivative2.fn create mode 100644 src/tpmc_mermaid.c create mode 100644 src/tpmc_mermaid.h create mode 100644 src/tpmc_pp.c create mode 100644 src/tpmc_pp.h diff --git a/docs/TPMC.drawio b/docs/TPMC.drawio new file mode 100644 index 0000000..25274e7 --- /dev/null +++ b/docs/TPMC.drawio @@ -0,0 +1,861 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fn/derivative.fn b/fn/derivative.fn new file mode 100644 index 0000000..2f4fadb --- /dev/null +++ b/fn/derivative.fn @@ -0,0 +1,20 @@ +let + typedef term { num(int) | + var(char) | + add(term, term) | + sub(term, term) | + mul(term, term) | + div(term, term) | + pow(term, term) } + fn deriv { + (x, x) { num(1) } + (num(_), _) { num(0) } + (pow(x, num(n)), x) { mul(num(n), pow(x, num(n - 1))) } + (add(f, g), x) { add(deriv(f, x), deriv(g, x)) } + (sub(f, g), x) { sub(deriv(f, x), deriv(g, x)) } + (mul(f, g), x) { add(mul(g, deriv(f, x)), mul(f, deriv(g, x))) } + (div(num(1), f), x) { div(sub(num(0), deriv(f, x)), mul(f, f)) } + (div(f, g), x) { div(sub(mul(g, deriv(f, x)), mul(f, deriv(g, x))), mul(g, g)) } + } +in + print(deriv(add(add(pow(var('x'), num(2)), var('x')), num(1)), var('x'))) diff --git a/fn/derivative2.fn b/fn/derivative2.fn new file mode 100644 index 0000000..c2d6512 --- /dev/null +++ b/fn/derivative2.fn @@ -0,0 +1,73 @@ +let + typedef term { num(int) | + var(char) | + add(term, term) | + sub(term, term) | + mul(term, term) | + div(term, term) | + pow(term, term) } + + fn deriv(t, x) { + if (t == x) { + num(1) + } else { + switch(t) { + (num(_)) { num(0) } + (pow(x1, num(n))) { + if (x1 == x) { + mul(num(n), pow(x1, num(n - 1))) + } else { + let t = simplify(x1); + in + if (t == x1) { + pow(t, num(n)) + } else { + deriv(pow(t, num(n)), x) + } + } + } + (add(f, g)) { add(deriv(f, x), deriv(g, x)) } + (sub(f, g)) { sub(deriv(f, x), deriv(g, x)) } + (mul(f, g)) { add(mul(g, deriv(f, x)), mul(f, deriv(g, x))) } + (div(num(1), f)) { div(sub(num(0), deriv(f, x)), mul(f, f)) } + (div(f, g)) { div(sub(mul(g, deriv(f, x)), mul(f, deriv(g, x))), mul(g, g)) } + } + } + } + + fn simplify { + (x=num(_)) { x } + (x=var(_)) { x } + (add(a, num(0))) | + (add(num(0), a)) { simplify(a) } + (add(num(a), num(b))) { num(a + b) } + (add(num(a), add(num(b), x))) | + (add(num(a), add(x, num(b)))) | + (add(add(x, num(b)), num(a))) | + (add(add(num(b), x), num(a))) { simplify(add(num(a + b), x)) } + (add(a, num(n))) | + (add(num(n), a)) { add(num(n), simplify(a)) } + (add(a, b)) { add(simplify(a), simplify(b)) } + (sub(a, num(0))) { simplify(a) } + (sub(a, num(n))) { sub(simplify(a), num(n)) } + (sub(a, b)) { sub(simplify(a), simplify(b)) } + (mul(num(0), _)) | + (mul(_, num(0))) { num(0) } + (mul(num(1), a)) | + (mul(a, num(1))) { simplify(a) } + (mul(num(a), num(b))) { num(a * b) } + (mul(a, num(n))) | + (mul(num(n), a)) { mul(num(n), simplify(a)) } + (mul(a, b)) { mul(simplify(a), simplify(b)) } + (div(a, num(1))) { simplify(a) } + (div(num(0), a)) { num(0) } + (div(a, b)) { div(simplify(a), simplify(b)) } + (pow(a, num(1))) { simplify(a) } + (pow(a, num(0))) { num(1) } + (pow(num(a), num(b))) { num(a**b) } + // (a + b)**2 == a**2 + 2ab + b**2 + (pow(add(a, b), num(2))) { simplify(add(pow(a, num(2)), add(mul(num(2), mul(a, b)), pow(b, num(2))))) } + (pow(a, b)) { pow(simplify(a), simplify(b)) } + } +in + print(simplify(simplify(deriv(add(add(pow(add(var('x'), num(1)), num(2)), var('x')), num(1)), var('x'))))) diff --git a/src/tpmc_mermaid.c b/src/tpmc_mermaid.c new file mode 100644 index 0000000..272c9c9 --- /dev/null +++ b/src/tpmc_mermaid.c @@ -0,0 +1,183 @@ +/* + * CEKF - VM supporting amb + * Copyright (C) 2022-2023 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 "symbol.h" +#include "tpmc_mermaid.h" + +int tpmc_mermaid_flag = 0; + +static char *mermaidState(TpmcState *state); +static void mermaidPattern(TpmcPattern *pattern); + +static bool seenName(char *name) { + static TpmcVariableTable *seen = NULL; + if (seen == NULL) { + seen = newTpmcVariableTable(); + PROTECT(seen); + } + HashSymbol *symbol = newSymbol(name); + if (getTpmcVariableTable(seen, symbol)) + return true; + setTpmcVariableTable(seen, symbol); + return false; +} + +static char *mermaidStateName(TpmcState *state) { + static char buf[512]; + switch (state->state->type) { + case TPMCSTATEVALUE_TYPE_TEST: + sprintf(buf, "T%d", state->stamp); + if (!seenName(buf)) { + printf("%s(\"%s\")\n", buf, + state->state->val.test->path->name); + } + break; + case TPMCSTATEVALUE_TYPE_FINAL: + sprintf(buf, "F%d", state->stamp); + if (!seenName(buf)) { + printf("%s(\"", buf); + ppLamExp(state->state->val.final->action); + printf("\")\n"); + } + break; + case TPMCSTATEVALUE_TYPE_ERROR: + sprintf(buf, "ERROR"); + printf("%s\n", buf); + break; + default: + cant_happen("unrecognised statevalue type %d in mermaidStateName", + state->state->type); + } + return strdup(buf); +} + +static void mermaidConstructorComponents(TpmcPatternArray *patterns) { + for (int i = 0; i < countTpmcPatternArray(patterns); ++i) { + mermaidPattern(patterns->entries[i]); + if (i < (countTpmcPatternArray(patterns) - 1)) { + printf(", "); + } + } +} + +static void mermaidPattern(TpmcPattern *pattern) { + printf("%s:", pattern->path->name); + TpmcPatternValue *value = pattern->pattern; + switch (value->type) { + case TPMCPATTERNVALUE_TYPE_VAR: + printf("var %s", value->val.var->name); + break; + case TPMCPATTERNVALUE_TYPE_COMPARISON: + mermaidPattern(value->val.comparison->previous); + printf("=="); + mermaidPattern(value->val.comparison->current); + break; + case TPMCPATTERNVALUE_TYPE_ASSIGNMENT: + printf("assignment"); + break; + case TPMCPATTERNVALUE_TYPE_WILDCARD: + printf("_"); + break; + case TPMCPATTERNVALUE_TYPE_CHARACTER: + printf("'%c'", value->val.character); + break; + case TPMCPATTERNVALUE_TYPE_BIGINTEGER: + fprintBigInt(stdout, value->val.biginteger); + break; + case TPMCPATTERNVALUE_TYPE_CONSTRUCTOR: + printf("%s(", value->val.constructor->tag->name); + mermaidConstructorComponents(value->val.constructor->components); + printf(")"); + break; + default: + cant_happen("unrecognised type %d in mermaidArcLabel", + value->type); + } +} + +static void mermaidArcLabel(TpmcArc *arc) { + printf("\""); + mermaidPattern(arc->test); + printf("\""); +} + +static void mermaidArc(char *stateName, TpmcArc *arc) { + char *targetState = mermaidState(arc->state); + printf("%s --", stateName); + mermaidArcLabel(arc); + printf("--> %s\n", targetState); + free(targetState); +} + +static void mermaidTestState(char *name, TpmcTestState *testState) { + for (int i = 0; i < countTpmcArcArray(testState->arcs); i++) { + mermaidArc(name, testState->arcs->entries[i]); + } +} + +static void mermaidFinalState(char *name + __attribute__((unused)), + TpmcFinalState *finalState + __attribute__((unused))) { + +} + +static void mermaidErrorState(char *name __attribute__((unused))) { +} + +static void mermaidStateValue(char *name, TpmcStateValue *value) { + if (value == NULL) { + return; + } + switch (value->type) { + case TPMCSTATEVALUE_TYPE_TEST: + mermaidTestState(name, value->val.test); + break; + case TPMCSTATEVALUE_TYPE_FINAL: + mermaidFinalState(name, value->val.final); + break; + case TPMCSTATEVALUE_TYPE_ERROR: + mermaidErrorState(name); + break; + default: + cant_happen + ("unrecognised statevalue type %d in mermaidStateValue", + value->type); + } +} + +static char *mermaidState(TpmcState *state) { + if (state == NULL) { + return ""; + } + char *name = mermaidStateName(state); + mermaidStateValue(name, state->state); + return name; +} + +void tpmcMermaid(TpmcState *state) { + if (tpmc_mermaid_flag) { + printf("## %p\n", state); + printf("```mermaid\n"); + printf("flowchart TD\n"); + free(mermaidState(state)); + printf("```\n"); + } +} diff --git a/src/tpmc_mermaid.h b/src/tpmc_mermaid.h new file mode 100644 index 0000000..94afcc6 --- /dev/null +++ b/src/tpmc_mermaid.h @@ -0,0 +1,26 @@ +#ifndef cekf_tpmc_mermaid_h +# define cekf_tpmc_mermaid_h +/* + * CEKF - VM supporting amb + * Copyright (C) 2022-2023 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 "tpmc.h" + +void tpmcMermaid(TpmcState *state); + +extern int tpmc_mermaid_flag; +#endif diff --git a/src/tpmc_pp.c b/src/tpmc_pp.c new file mode 100644 index 0000000..1e31331 --- /dev/null +++ b/src/tpmc_pp.c @@ -0,0 +1,226 @@ +/* + * CEKF - VM supporting amb + * Copyright (C) 2022-2023 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 "tpmc_pp.h" +#include "common.h" + +void ppTpmcComparisonPattern(TpmcComparisonPattern *comparisonPattern) { + ppTpmcPattern(comparisonPattern->previous); + eprintf("=="); + ppTpmcPattern(comparisonPattern->current); +} + +void ppTpmcAssignmentPattern(TpmcAssignmentPattern *assignmentPattern) { + eprintf("%s<-", assignmentPattern->name->name); + ppTpmcPattern(assignmentPattern->value); +} + +void ppTpmcConstructorPattern(TpmcConstructorPattern *constructorPattern) { + ppTpmcSymbol(constructorPattern->tag); + ppTpmcPatternArray(constructorPattern->components); +} + +void ppTpmcPatternArray(TpmcPatternArray *patternArray) { + eprintf("("); + int i = 0; + TpmcPattern *pattern = NULL; + bool more = false; + while (iterateTpmcPatternArray(patternArray, &i, &pattern, &more)) { + ppTpmcPattern(pattern); + if (more) { + eprintf(", "); + } + } + eprintf(")"); +} + +void ppTpmcPatternValue(TpmcPatternValue *patternValue) { + if (patternValue == NULL) { + eprintf(""); + return; + } + switch (patternValue->type) { + case TPMCPATTERNVALUE_TYPE_VAR: + ppTpmcSymbol(patternValue->val.var); + break; + case TPMCPATTERNVALUE_TYPE_COMPARISON: + ppTpmcComparisonPattern(patternValue->val.comparison); + break; + case TPMCPATTERNVALUE_TYPE_ASSIGNMENT: + ppTpmcAssignmentPattern(patternValue->val.assignment); + break; + case TPMCPATTERNVALUE_TYPE_WILDCARD: + eprintf("_"); + break; + case TPMCPATTERNVALUE_TYPE_CHARACTER: + eprintf("'%c'", patternValue->val.character); + break; + case TPMCPATTERNVALUE_TYPE_BIGINTEGER: + fprintBigInt(errout, patternValue->val.biginteger); + break; + case TPMCPATTERNVALUE_TYPE_CONSTRUCTOR: + ppTpmcConstructorPattern(patternValue->val.constructor); + break; + } +} + +void ppTpmcPattern(TpmcPattern *pattern) { + if (pattern == NULL) { + eprintf(""); + return; + } + if (pattern->path == NULL) { + eprintf("=("); + } else { + eprintf("%s=(", pattern->path->name); + } + ppTpmcPatternValue(pattern->pattern); + eprintf(")"); +} + +void ppTpmcMatrix(TpmcMatrix *matrix) { + if (matrix == NULL) { + eprintf("\n"); + return; + } + eprintf("TpmcMatrix[\n"); + for (int height = 0; height < matrix->height; height++) { + eprintf(" ("); + for (int width = 0; width < matrix->width; width++) { + ppTpmcPattern(getTpmcMatrixIndex(matrix, width, height)); + if (width + 1 < matrix->width) + eprintf(", "); + } + eprintf(")\n"); + } + eprintf("]\n"); +} + +static char getTpmcStateType(TpmcState *state) { + switch (state->state->type) { + case TPMCSTATEVALUE_TYPE_TEST: + return 'T'; + case TPMCSTATEVALUE_TYPE_FINAL: + return 'F'; + case TPMCSTATEVALUE_TYPE_ERROR: + return 'E'; + default: + return '?'; + } +} + +void ppTpmcState(TpmcState *state) { + eprintf("%c%d(%d) ", getTpmcStateType(state), state->stamp, + state->refcount); + ppTpmcVariableTable(state->freeVariables); + eprintf(" "); + ppTpmcStateValue(state->state); +} + +void ppTpmcVariableTable(TpmcVariableTable *table) { + eprintf("["); + if (table != NULL) { + int i = 0; + int count = 0; + HashSymbol *symbol; + while ((symbol = iterateTpmcVariableTable(table, &i)) != NULL) { + ppTpmcSymbol(symbol); + count++; + if (count < countTpmcVariableTable(table)) { + eprintf(", "); + } + } + } + eprintf("]"); +} + +void ppTpmcSymbol(HashSymbol *symbol) { + eprintf("%s", symbol->name); +} + +void ppTpmcStateValue(TpmcStateValue *value) { + switch (value->type) { + case TPMCSTATEVALUE_TYPE_TEST: + ppTpmcTestState(value->val.test); + break; + case TPMCSTATEVALUE_TYPE_FINAL: + ppTpmcFinalState(value->val.final); + break; + case TPMCSTATEVALUE_TYPE_ERROR: + eprintf("ERROR"); + break; + } +} + +void ppTpmcTestState(TpmcTestState *test) { + ppTpmcSymbol(test->path); + eprintf(":"); + ppTpmcArcArray(test->arcs); +} + +void ppTpmcArcArray(TpmcArcArray *arcs) { + eprintf("{"); + int i = 0; + TpmcArc *arc; + bool more; + while (iterateTpmcArcArray(arcs, &i, &arc, &more)) { + ppTpmcArc(arc); + if (more) + eprintf(", "); + } + eprintf("}"); +} + +void ppTpmcArc(TpmcArc *arc) { + eprintf("ARC("); + ppTpmcVariableTable(arc->freeVariables); + eprintf("::"); + ppTpmcPattern(arc->test); + eprintf("=>"); + ppTpmcState(arc->state); + eprintf(")"); +} + +void ppTpmcFinalState(TpmcFinalState *final) { + ppLamExp(final->action); +} + +void ppTpmcIntArray(TpmcIntArray *array) { + eprintf("["); + int i = 0; + int entry; + bool more; + while (iterateTpmcIntArray(array, &i, &entry, &more)) { + eprintf("%d%s", entry, more ? ", " : ""); + } + eprintf("]"); +} + +void ppTpmcStateArray(TpmcStateArray *array) { + eprintf("[\n"); + int i = 0; + TpmcState *state; + bool more; + while (iterateTpmcStateArray(array, &i, &state, &more)) { + eprintf(" "); + ppTpmcState(state); + if (more) + eprintf(",\n"); + } + eprintf("\n]"); +} diff --git a/src/tpmc_pp.h b/src/tpmc_pp.h new file mode 100644 index 0000000..90cc536 --- /dev/null +++ b/src/tpmc_pp.h @@ -0,0 +1,41 @@ +#ifndef cekf_tpmc_pp_h +# define cekf_tpmc_pp_h +/* + * CEKF - VM supporting amb + * Copyright (C) 2022-2023 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 "tpmc.h" + +void ppTpmcMatrix(TpmcMatrix *matrix); +void ppTpmcPattern(TpmcPattern *pattern); +void ppTpmcPatternValue(TpmcPatternValue *patternValue); +void ppTpmcComparisonPattern(TpmcComparisonPattern *comparisonPattern); +void ppTpmcAssignmentPattern(TpmcAssignmentPattern *assignmentPattern); +void ppTpmcConstructorPattern(TpmcConstructorPattern *constructorPattern); +void ppTpmcPatternArray(TpmcPatternArray *patternArray); +void ppTpmcState(TpmcState *state); +void ppTpmcVariableTable(TpmcVariableTable *table); +void ppTpmcSymbol(HashSymbol *symbol); +void ppTpmcStateValue(TpmcStateValue *value); +void ppTpmcTestState(TpmcTestState *test); +void ppTpmcArcArray(TpmcArcArray *arcs); +void ppTpmcArc(TpmcArc *arc); +void ppTpmcFinalState(TpmcFinalState *final); +void ppTpmcIntArray(TpmcIntArray *array); +void ppTpmcStateArray(TpmcStateArray *array); + +#endif From 587ba173b4c6dbdfe1f71813679a711bd457e6e9 Mon Sep 17 00:00:00 2001 From: Bill Hails Date: Fri, 29 Mar 2024 11:03:01 +0000 Subject: [PATCH 27/33] cant_happen now reports file and line number --- src/common.h | 6 ++++-- src/errors.c | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/common.h b/src/common.h index d37ca15..01aab36 100644 --- a/src/common.h +++ b/src/common.h @@ -63,13 +63,15 @@ typedef uint32_t hash_t; # define __attribute__(x) # endif # define errout stdout -void cant_happen(const char *message, ...) - __attribute__((noreturn, format(printf, 1, 2))); +void _cant_happen(char *file, int line, const char *message, ...) + __attribute__((noreturn, format(printf, 3, 4))); void can_happen(const char *message, ...) __attribute__((format(printf, 1, 2))); void eprintf(const char *message, ...) __attribute__((format(printf, 1, 2))); bool hadErrors(void); +#define cant_happen(...) _cant_happen(__FILE__, __LINE__, __VA_ARGS__) + # define PAD_WIDTH 2 #endif diff --git a/src/errors.c b/src/errors.c index 0aa9c5f..9828098 100644 --- a/src/errors.c +++ b/src/errors.c @@ -28,12 +28,12 @@ static bool errors = false; -void cant_happen(const char *message, ...) { +void _cant_happen(char *file, int line, const char *message, ...) { va_list args; va_start(args, message); vfprintf(errout, message, args); va_end(args); - eprintf("\n"); + eprintf(" at %s line %d\n", file, line); #ifdef DEBUG_DUMP_CORE abort(); #else From 376ab1893642ea62c17460573efb90a369ed426c Mon Sep 17 00:00:00 2001 From: Bill Hails Date: Sat, 30 Mar 2024 15:10:26 +0000 Subject: [PATCH 28/33] clean up and minor bug-fixes --- docs/TPMC.drawio | 503 ++++++++++++++++++++++---------------- docs/lambda-conversion.md | 79 ++++++ fn/derivative3.fn | 9 + fn/dictionary.fn | 4 +- fn/member2.fn | 8 + src/common.h | 2 - src/hash.h | 2 + src/lambda_pp.c | 2 +- src/tc.yaml | 1 + src/tc_analyze.c | 18 +- src/tc_helper.c | 5 +- src/tpmc_logic.c | 1 - src/tpmc_match.c | 215 ++++++++-------- src/tpmc_mermaid.c | 58 +++-- src/tpmc_pp.c | 11 +- src/tpmc_translate.c | 21 +- 16 files changed, 578 insertions(+), 361 deletions(-) create mode 100644 fn/derivative3.fn create mode 100644 fn/member2.fn diff --git a/docs/TPMC.drawio b/docs/TPMC.drawio index 25274e7..ed9f370 100644 --- a/docs/TPMC.drawio +++ b/docs/TPMC.drawio @@ -1,9 +1,15 @@ - + - + + + + + + + @@ -301,7 +307,7 @@ - + @@ -325,268 +331,268 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -595,91 +601,91 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -688,10 +694,10 @@ - + - + @@ -700,160 +706,229 @@ - + - + - + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - + - - + + - - + + - - + + - - + + - - + + - + - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - + + - - + + diff --git a/docs/lambda-conversion.md b/docs/lambda-conversion.md index 2824aaf..e8ce4ee 100644 --- a/docs/lambda-conversion.md +++ b/docs/lambda-conversion.md @@ -642,3 +642,82 @@ And it's working! At least the python prototype [TPMC2.py](../prototyping/TPMC2. (let (p1$2 (vec 2 p1)) E3))))))))) ``` + +### Extending TPMC to Support Comparison + +The language requires an addition, if possible to the kinds of pattern matching available. +Specific example is `member` + +``` +let + fn member { + (_, []) { false } + (x, x @ _) { true } + (x, _ @ t) { member(x, t) } + } +in + member('c', "abc") +``` + +Where the second match succeeds if the first argument equals the head of the second argument. + +While I thought I had this working, simply treating comparison as a new kind of "constructor", +in fact in my tests it was only working accidentally. +In general there is no guarantee that the variable representing the thing being compared is +in scope when the comparison happens. In the above example x in the second match is only in scope +because it is bound at the top level. + +In the original algorithm variables are brought in to scope by the conversion of the arc pattern. +But the non-locality of the variable being compared causes problems. + +``` +let + typedef baz { foo(int) | bar(baz) } + fn fail { + (x, x) { 1 } + (bar(x), x) { 2 } + } +in + print(fail(foo(1), foo(1))) +### +undefined variable p$15$0 in analyzeVar +``` + +The intermediate code generated is +```scheme +(lambda (p$15 p$16) + (letrec (($tpmc38 (lambda () (error)))) + (if (eq p$15 p$16) + (begin 1) + (if (eq p$15$0 p$16) + (match (tag p$15) + ((1:bar) (begin 2)) + ((0:foo) ($tpmc38))) + ($tpmc38))))) +``` + +So walking through, the matrix will be + +``` +(p$15, p$16==p$15) +(p$15=bar(p$15$0), p$16==p$15$0) + +The mixture rule applies on row 1 column 2 because it is a comparison +not just a var. + +N is + +``` +p$16==p$15 +p$16==p$15$0 +``` + +M-N is + +``` +(p$15 ) +(p$15=bar(p$15$0)) +``` + +both rows match so the indices are {1, 2} + diff --git a/fn/derivative3.fn b/fn/derivative3.fn new file mode 100644 index 0000000..d67e084 --- /dev/null +++ b/fn/derivative3.fn @@ -0,0 +1,9 @@ +let + typedef baz { foo(int) | bar(baz) } + fn fail { + (x, x) { 1 } + (bar(x), x) { 2 } + (_, _) { 3 } + } +in + print(fail(foo(1), foo(1))) diff --git a/fn/dictionary.fn b/fn/dictionary.fn index 191ef61..03624fc 100644 --- a/fn/dictionary.fn +++ b/fn/dictionary.fn @@ -9,7 +9,6 @@ let (B, D(R, a, x, D(R, b, y, c)), z, d) | (B, a, x, D(R, D(R, b, y, c), z, d)) | (B, a, x, D(R, b, y, D(R, c, z, d))) { D(R, D(B, a, x, b), y, D(B, c, z, d)) } - (BB, D(R, a, x, D(R, b, y, c)), z, d) | (BB, D(R, a, x, D(R, b, y, c)), z, d) { D(B, D(B, a, x, b), y, D(B, c, z, d)) } (color, a, b, c) { D(color, a, b, c) } @@ -125,4 +124,5 @@ let } in - lookup('f', delete('f', makeDict("kgimtseettepmupybbbmplgntqzutrfxqarki"))) + print(lookup('f', delete('k', makeDict("kgimtseettepmupybbbmplgntqzutrfxqarki")))); + puts("\n") diff --git a/fn/member2.fn b/fn/member2.fn new file mode 100644 index 0000000..8dfe470 --- /dev/null +++ b/fn/member2.fn @@ -0,0 +1,8 @@ +let + fn member2 { + ([], _) { false } + (item @ t, item) { true } + (_ @ tail, item) { member2(tail, item) } + } +in + member2("abc", 'c') diff --git a/src/common.h b/src/common.h index 01aab36..0411cd4 100644 --- a/src/common.h +++ b/src/common.h @@ -22,8 +22,6 @@ # include # include -typedef uint32_t hash_t; - # define DEBUG_ANY # ifdef DEBUG_ANY diff --git a/src/hash.h b/src/hash.h index 8b9c126..3c5623f 100644 --- a/src/hash.h +++ b/src/hash.h @@ -26,6 +26,8 @@ # define HASH_MAX_LOAD 0.75 +typedef uint32_t hash_t; + typedef struct HashSymbol { struct Header header; hash_t hash; diff --git a/src/lambda_pp.c b/src/lambda_pp.c index 244a4d3..44ae11f 100644 --- a/src/lambda_pp.c +++ b/src/lambda_pp.c @@ -656,7 +656,7 @@ void ppLamConstant(LamConstant *constant) { void ppLamDeconstruct(LamDeconstruct *deconstruct) { eprintf("(deconstruct "); ppHashSymbol(deconstruct->name); - eprintf("[%d]", deconstruct->vec); + eprintf("[%d] ", deconstruct->vec); ppLamExp(deconstruct->exp); eprintf(")"); } diff --git a/src/tc.yaml b/src/tc.yaml index 8dd5fcf..2836ab6 100644 --- a/src/tc.yaml +++ b/src/tc.yaml @@ -69,6 +69,7 @@ unions: smallinteger: void_ptr biginteger: void_ptr character: void_ptr + unknown: HashSymbol userType: TcUserType primitives: !include primitives.yaml diff --git a/src/tc_analyze.c b/src/tc_analyze.c index 8e440c1..3b00a14 100644 --- a/src/tc_analyze.c +++ b/src/tc_analyze.c @@ -46,6 +46,7 @@ static TcType *makeStarship(void); static TcType *makeSmallInteger(void); static TcType *makeBigInteger(void); static TcType *makeCharacter(void); +static TcType *makeUnknown(HashSymbol *var); static TcType *makeFreshVar(char *name __attribute__((unused))); static TcType *makeVar(HashSymbol *t); static TcType *makeFn(TcType *arg, TcType *result); @@ -249,6 +250,7 @@ static TcType *analyzeVar(HashSymbol *var, TcEnv *env, TcNg *ng) { TcType *res = lookup(env, var, ng); if (res == NULL) { can_happen("undefined variable %s in analyzeVar", var->name); + return makeUnknown(var); } // LEAVE(analyzeVar); return res; @@ -1245,6 +1247,7 @@ static TcType *freshRec(TcType *type, TcNg *ng, TcTypeTable *map) { case TCTYPE_TYPE_SMALLINTEGER: case TCTYPE_TYPE_BIGINTEGER: case TCTYPE_TYPE_CHARACTER: + case TCTYPE_TYPE_UNKNOWN: return type; case TCTYPE_TYPE_USERTYPE:{ TcType *res = freshUserType(type->val.userType, ng, map); @@ -1343,6 +1346,11 @@ static TcType *makeBigInteger() { return res; } +static TcType *makeUnknown(HashSymbol *var) { + TcType *res = newTcType(TCTYPE_TYPE_UNKNOWN, TCTYPE_VAL_UNKNOWN(var)); + return res; +} + static TcType *makeCharacter() { TcType *res = newTcType(TCTYPE_TYPE_CHARACTER, TCTYPE_VAL_CHARACTER()); return res; @@ -1508,8 +1516,11 @@ static bool unifyUserTypes(TcUserType *a, TcUserType *b) { static bool _unify(TcType *a, TcType *b) { a = prune(a); b = prune(b); - if (a == b) + if (a == b) { + if (a->type == TCTYPE_TYPE_UNKNOWN) + return false; return true; + } if (a->type == TCTYPE_TYPE_VAR) { if (b->type != TCTYPE_TYPE_VAR) { if (occursInType(a, b)) { @@ -1545,6 +1556,8 @@ static bool _unify(TcType *a, TcType *b) { case TCTYPE_TYPE_BIGINTEGER: case TCTYPE_TYPE_CHARACTER: return true; + case TCTYPE_TYPE_UNKNOWN: + return false; case TCTYPE_TYPE_USERTYPE: return unifyUserTypes(a->val.userType, b->val.userType); default: @@ -1635,6 +1648,8 @@ static bool sameType(TcType *a, TcType *b) { case TCTYPE_TYPE_SMALLINTEGER: case TCTYPE_TYPE_CHARACTER: return true; + case TCTYPE_TYPE_UNKNOWN: + return false; case TCTYPE_TYPE_USERTYPE: return sameUserType(a->val.userType, b->val.userType); default: @@ -1680,6 +1695,7 @@ static bool occursIn(TcType *a, TcType *b) { case TCTYPE_TYPE_SMALLINTEGER: case TCTYPE_TYPE_BIGINTEGER: case TCTYPE_TYPE_CHARACTER: + case TCTYPE_TYPE_UNKNOWN: return false; case TCTYPE_TYPE_USERTYPE: return occursInUserType(a, b->val.userType); diff --git a/src/tc_helper.c b/src/tc_helper.c index 48fa050..4c5c2ba 100644 --- a/src/tc_helper.c +++ b/src/tc_helper.c @@ -43,11 +43,14 @@ void ppTcType(TcType *type) { case TCTYPE_TYPE_CHARACTER: eprintf("char"); break; + case TCTYPE_TYPE_UNKNOWN: + eprintf("unknown:%s", type->val.unknown->name); + break; case TCTYPE_TYPE_USERTYPE: ppTcUserType(type->val.userType); break; default: - cant_happen("unrecognized type %d in ppTcType", type->type); + eprintf("unrecognized type %d", type->type); } } diff --git a/src/tpmc_logic.c b/src/tpmc_logic.c index addbc67..cf87575 100644 --- a/src/tpmc_logic.c +++ b/src/tpmc_logic.c @@ -554,7 +554,6 @@ static LamVarList *arrayToVarList(TpmcVariableArray *array) { LamLam *tpmcConvert(int nargs, int nbodies, AstArgList **argLists, LamExp **actions, LamContext *env) { - system("clear"); TpmcVariableArray *rootVariables = createRootVariables(nargs); int save = PROTECT(rootVariables); TpmcMatchRuleArray *rules = diff --git a/src/tpmc_match.c b/src/tpmc_match.c index 0a33532..4a6bd1e 100644 --- a/src/tpmc_match.c +++ b/src/tpmc_match.c @@ -20,6 +20,7 @@ #include #include +#include #include "common.h" #include "tpmc_match.h" #include "tpmc_compare.h" @@ -35,27 +36,27 @@ # include "debugging_off.h" #endif +static TpmcState *match(TpmcMatrix *matrix, TpmcStateArray *finalStates, + TpmcState *errorState, TpmcStateArray *knownStates); + +TpmcState *tpmcMatch(TpmcMatrix *matrix, TpmcStateArray *finalStates, + TpmcState *errorState, TpmcStateArray *knownStates) { +#ifdef DEBUG_TPMC_MATCH + system("clear"); +#endif + return match(matrix, finalStates, errorState, knownStates); +} + TpmcState *tpmcMakeState(TpmcStateValue *val) { static int counter = 0; return newTpmcState(counter++, val); } -// this is definately a wildcard -// TPMCPATTERNVALUE_TYPE_WILDCARD -// -// TPMCPATTERNVALUE_TYPE_COMPARISON -// -// these are all constructors: -// TPMCPATTERNVALUE_TYPE_CHARACTER -// TPMCPATTERNVALUE_TYPE_INTEGER -// TPMCPATTERNVALUE_TYPE_CONSTRUCTOR - static bool patternIsWildcard(TpmcPattern *pattern) { - bool res = pattern->pattern->type == TPMCPATTERNVALUE_TYPE_WILDCARD; - return res; + return pattern->pattern->type == TPMCPATTERNVALUE_TYPE_WILDCARD; } -static bool noRemainingTests(TpmcMatrix *matrix) { +static bool topRowOnlyVariables(TpmcMatrix *matrix) { for (int x = 0; x < matrix->width; x++) { if (!patternIsWildcard(getTpmcMatrixIndex(matrix, x, 0))) { return false; @@ -67,6 +68,7 @@ static bool noRemainingTests(TpmcMatrix *matrix) { static int findFirstConstructorColumn(TpmcMatrix *matrix) { for (int x = 0; x < matrix->width; x++) { if (!patternIsWildcard(getTpmcMatrixIndex(matrix, x, 0))) { + DEBUG("findFirstConstructorColumn(%d x %d) => %d", matrix->width, matrix->height, x); return x; } } @@ -81,9 +83,9 @@ static TpmcState *makeEmptyTestState(HashSymbol *path) { TpmcStateValue *val = newTpmcStateValue(TPMCSTATEVALUE_TYPE_TEST, TPMCSTATEVALUE_VAL_TEST(test)); PROTECT(val); - TpmcState *state = tpmcMakeState(val); + TpmcState *testState = tpmcMakeState(val); UNPROTECT(save); - return state; + return testState; } static bool patternMatches(TpmcPattern *constructor, TpmcPattern *pattern) { @@ -91,7 +93,7 @@ static bool patternMatches(TpmcPattern *constructor, TpmcPattern *pattern) { (constructor->pattern->type == TPMCPATTERNVALUE_TYPE_COMPARISON); switch (pattern->pattern->type) { case TPMCPATTERNVALUE_TYPE_VAR: - cant_happen("patternMatches ennncountered var"); + cant_happen("patternMatches encountered var"); case TPMCPATTERNVALUE_TYPE_COMPARISON: return eqTpmcPattern(constructor, pattern); case TPMCPATTERNVALUE_TYPE_ASSIGNMENT: @@ -144,8 +146,8 @@ TpmcIntArray *findPatternsMatching(TpmcPattern *c, TpmcPatternArray *N) { return res; } -static TpmcPatternArray *extractColumnSubset(TpmcPatternArray *N, - TpmcIntArray *ys) { +static TpmcPatternArray *extractColumnSubset(TpmcIntArray *ys, + TpmcPatternArray *N) { TpmcPatternArray *res = newTpmcPatternArray("extractColumnSubset"); int save = PROTECT(res); int i = 0; @@ -157,7 +159,7 @@ static TpmcPatternArray *extractColumnSubset(TpmcPatternArray *N, return res; } -static TpmcPatternArray *extractMatrixColumn(TpmcMatrix *matrix, int x) { +static TpmcPatternArray *extractMatrixColumn(int x, TpmcMatrix *matrix) { TpmcPatternArray *res = newTpmcPatternArray("extractMatrixColumn"); int save = PROTECT(res); for (int y = 0; y < matrix->height; y++) { @@ -167,7 +169,7 @@ static TpmcPatternArray *extractMatrixColumn(TpmcMatrix *matrix, int x) { return res; } -static TpmcMatrix *discardMatrixColumn(TpmcMatrix *matrix, int column) { +static TpmcMatrix *discardMatrixColumn(int column, TpmcMatrix *matrix) { TpmcMatrix *res = newTpmcMatrix(matrix->width - 1, matrix->height); int save = PROTECT(res); for (int x = 0; x < matrix->width; x++) { @@ -187,8 +189,8 @@ static TpmcMatrix *discardMatrixColumn(TpmcMatrix *matrix, int column) { return res; } -static TpmcMatrix *extractMatrixRows(TpmcMatrix *matrix, - TpmcIntArray *indices) { +static TpmcMatrix *extractMatrixRows(TpmcIntArray *indices, + TpmcMatrix *matrix) { TpmcMatrix *res = newTpmcMatrix(matrix->width, indices->size); int save = PROTECT(res); int resy = 0; @@ -230,8 +232,7 @@ static TpmcMatrix *appendMatrices(TpmcMatrix *prefix, TpmcMatrix *suffix) { return res; } -static TpmcStateArray *extractStateArraySubset(TpmcStateArray *all, - TpmcIntArray *indices) { +static TpmcStateArray *extractStateArraySubset(TpmcIntArray *indices, TpmcStateArray *all) { TpmcStateArray *res = newTpmcStateArray("extractStateArraySubset"); int save = PROTECT(res); for (int i = 0; i < indices->size; ++i) { @@ -242,7 +243,7 @@ static TpmcStateArray *extractStateArraySubset(TpmcStateArray *all, return res; } -static int determineArity(TpmcPattern *pattern) { +static int arityOf(TpmcPattern *pattern) { if (pattern->pattern->type == TPMCPATTERNVALUE_TYPE_CONSTRUCTOR) { LamTypeConstructorInfo *info = pattern->pattern->val.constructor->info; @@ -467,9 +468,7 @@ static void collectPathsBoundByPattern(TpmcPattern *pattern, case TPMCPATTERNVALUE_TYPE_ASSIGNMENT: cant_happen("collectPathsBoundByPattern encountered ASSIGNMENT"); case TPMCPATTERNVALUE_TYPE_WILDCARD: - break; case TPMCPATTERNVALUE_TYPE_CHARACTER: - break; case TPMCPATTERNVALUE_TYPE_BIGINTEGER: break; case TPMCPATTERNVALUE_TYPE_CONSTRUCTOR:{ @@ -537,7 +536,15 @@ static TpmcVariableTable *getStatesFreeVariables(TpmcState *state) { return state->freeVariables; } -static TpmcArc *makeTpmcArc(TpmcState *state, TpmcPattern *pattern) { +static void addFreeVariablesRequiredByPattern(TpmcPattern *pattern, TpmcVariableTable *freeVariables) { + if (pattern->pattern->type == TPMCPATTERNVALUE_TYPE_COMPARISON) { + TpmcPattern *previous = pattern->pattern->val.comparison->previous; + HashSymbol *name = previous->path; + setTpmcVariableTable(freeVariables, name); + } +} + +static TpmcArc *makeTpmcArc(TpmcPattern *pattern, TpmcState *state) { TpmcArc *arc = newTpmcArc(state, pattern); int save = PROTECT(arc); // the free variables of an arc are the free variables of its state minus the variables bound in the pattern @@ -552,141 +559,123 @@ static TpmcArc *makeTpmcArc(TpmcState *state, TpmcPattern *pattern) { setTpmcVariableTable(arc->freeVariables, key); } } + addFreeVariablesRequiredByPattern(pattern, arc->freeVariables); state->refcount++; UNPROTECT(save); return arc; } +static TpmcIntArray *findWcIndices(TpmcPatternArray *N) { + TpmcIntArray *wcIndices = newTpmcIntArray(); + int save = PROTECT(wcIndices); + int row = 0; + TpmcPattern *candidate; + while (iterateTpmcPatternArray(N, &row, &candidate, NULL)) { + if (patternIsWildcard(candidate)) { + pushTpmcIntArray(wcIndices, row - 1); + } + } + UNPROTECT(save); + return wcIndices; +} + static TpmcState *mixture(TpmcMatrix *M, TpmcStateArray *finalStates, TpmcState *errorState, TpmcStateArray *knownStates) { ENTER(mixture); // there is some column N whose topmost pattern is a constructor - int index = findFirstConstructorColumn(M); - DEBUG("mixture found constructor in column %d of %dx%d", index, M->width, M->height); - TpmcPatternArray *N = extractMatrixColumn(M, index); + int firstConstructorColumn = findFirstConstructorColumn(M); + TpmcPatternArray *N = extractMatrixColumn(firstConstructorColumn, M); int save = PROTECT(N); - DEBUGN("mixture extracted column %d: ", index); - IFDEBUGN(ppTpmcPatternArray(N)); - TpmcMatrix *MN = discardMatrixColumn(M, index); + // let M-N be all the columns in M except N + TpmcMatrix *MN = discardMatrixColumn(firstConstructorColumn, M); PROTECT(MN); // The goal is to build a test state with the variable v and some outgoing arcs // (one for each constructor and possibly a default arc). - TpmcState *state = makeEmptyTestState(N->entries[0]->path); - PROTECT(state); - // For each constructor c in the selected column, its arc is defined as follows: + TpmcState *testState = makeEmptyTestState(N->entries[0]->path); + PROTECT(testState); for (int row = 0; row < N->size; row++) { TpmcPattern *c = N->entries[row]; + // For each constructor c in the selected column, its arc is defined as follows: if (!patternIsWildcard(c)) { - DEBUGN("mixture considering pattern on row %d ", row); - IFDEBUGN(ppTpmcPattern(c)); // Let {i1 , ... , ij} be the row-indices of the patterns in N that match c. TpmcIntArray *matchingIndices = findPatternsMatching(c, N); int save2 = PROTECT(matchingIndices); // Let {pat1 , ... , patj} be the patterns in the column corresponding to the indices computed above, - TpmcPatternArray *matchingPatterns = - extractColumnSubset(N, matchingIndices); + TpmcPatternArray *matchingPatterns = extractColumnSubset(matchingIndices, N); PROTECT(matchingPatterns); // let n be the arity of the constructor c - int arity = determineArity(c); - DEBUG("arity %d\n", arity); + int n = arityOf(c); // For each pati, its n sub-patterns are extracted; // if pati is a wildcard, n wildcards are produced instead, each tagged with the right path variable. - TpmcMatrix *subPatternMatrix = - makeSubPatternMatrix(matchingPatterns, arity); + TpmcMatrix *subPatternMatrix = makeSubPatternMatrix(matchingPatterns, n); PROTECT(subPatternMatrix); // This matrix is then appended to the result of selecting, from each column in MN, // those rows whose indices are in {i1 , ... , ij}. - TpmcMatrix *prefixMatrix = extractMatrixRows(MN, matchingIndices); + TpmcMatrix *prefixMatrix = extractMatrixRows(matchingIndices, MN); PROTECT(prefixMatrix); - TpmcMatrix *newMatrix = - appendMatrices(prefixMatrix, subPatternMatrix); + TpmcMatrix *newMatrix = appendMatrices(prefixMatrix, subPatternMatrix); PROTECT(newMatrix); // Finally the indices are used to select the corresponding final states that go with these rows. - TpmcStateArray *newFinalStates = - extractStateArraySubset(finalStates, matchingIndices); + TpmcStateArray *newFinalStates = extractStateArraySubset(matchingIndices, finalStates); PROTECT(newFinalStates); // The arc for the constructor c is now defined as (c’,state), where c’ is c with any immediate // sub-patterns replaced by their path variables (thus c’ is a simple pattern) TpmcPattern *cPrime = replaceComponentsWithWildcards(c); PROTECT(cPrime); // and state is the result of recursively applying match to the new matrix and the new sequence of final states - DEBUG("mixture calling match for normal case, column %d row %d of %dx%d", index, row, M->width, M->height); - TpmcState *newState = - tpmcMatch(newMatrix, newFinalStates, errorState, knownStates); + TpmcState *newState = match(newMatrix, newFinalStates, errorState, knownStates); PROTECT(newState); - TpmcArc *arc = makeTpmcArc(newState, cPrime); + TpmcArc *arc = makeTpmcArc(cPrime, newState); PROTECT(arc); - if (tpmcArcInArray(arc, state->state->val.test->arcs)) { + if (tpmcArcInArray(arc, testState->state->val.test->arcs)) { arc->state->refcount--; validateLastAlloc(); } else { - DEBUGN("mixture constructed new arc: "); - IFDEBUGN(ppTpmcArc(arc)); - pushTpmcArcArray(state->state->val.test->arcs, arc); + pushTpmcArcArray(testState->state->val.test->arcs, arc); } UNPROTECT(save2); } } // Finally, the possibility for matching failure is considered. // If the set of constructors is exhaustive, then no more arcs are computed - if (constructorsAreExhaustive(state)) { - TpmcState *res = deduplicateState(state, knownStates); - UNPROTECT(save); - LEAVE(mixture); - return res; - } - // Otherwise, a default arc (_,state) is the last arc. - // If there are any wildcard patterns in the selected column - TpmcIntArray *wcIndices = newTpmcIntArray(); - PROTECT(wcIndices); - int row = 0; - TpmcPattern *candidate; - while (iterateTpmcPatternArray(N, &row, &candidate, NULL)) { - if (patternIsWildcard(candidate)) { - pushTpmcIntArray(wcIndices, row - 1); + if (!constructorsAreExhaustive(testState)) { + // Otherwise, a default arc (_,state) is the last arc. + // If there are any wildcard patterns in the selected column + TpmcIntArray *wcIndices = findWcIndices(N); + PROTECT(wcIndices); + if (countTpmcIntArray(wcIndices) > 0) { + // then their rows are selected from the rest of the matrix and the final states + TpmcMatrix *wcMatrix = extractMatrixRows(wcIndices, MN); + PROTECT(wcMatrix); + TpmcStateArray *wcFinalStates = extractStateArraySubset(wcIndices, finalStates); + PROTECT(wcFinalStates); + // and the state is the result of applying match to the new matrix and states + TpmcState *wcState = match(wcMatrix, wcFinalStates, errorState, knownStates); + PROTECT(wcState); + TpmcPattern *wcPattern = makeNamedWildcardPattern(N->entries[0]->path); + PROTECT(wcPattern); + TpmcArc *wcArc = makeTpmcArc(wcPattern, wcState); + PROTECT(wcArc); + pushTpmcArcArray(testState->state->val.test->arcs, wcArc); + } else { + validateLastAlloc(); + // Otherwise, the error state is used after its reference count has been incremented + TpmcPattern *errorPattern = makeNamedWildcardPattern(N->entries[0]->path); + PROTECT(errorPattern); + TpmcArc *errorArc = makeTpmcArc(errorPattern, errorState); + PROTECT(errorArc); + pushTpmcArcArray(testState->state->val.test->arcs, errorArc); } } - if (countTpmcIntArray(wcIndices) > 0) { - // then their rows are selected from the rest of the matrix and the final states - TpmcMatrix *wcMatrix = extractMatrixRows(MN, wcIndices); - PROTECT(wcMatrix); - TpmcStateArray *wcFinalStates = - extractStateArraySubset(finalStates, wcIndices); - PROTECT(wcFinalStates); - // and the state is the result of applying match to the new matrix and states - DEBUG("mixture calling match for error case"); - TpmcState *wcState = - tpmcMatch(wcMatrix, wcFinalStates, errorState, knownStates); - PROTECT(wcState); - TpmcPattern *wcPattern = - makeNamedWildcardPattern(N->entries[0]->path); - PROTECT(wcPattern); - TpmcArc *wcArc = makeTpmcArc(wcState, wcPattern); - PROTECT(wcArc); - pushTpmcArcArray(state->state->val.test->arcs, wcArc); - TpmcState *res = deduplicateState(state, knownStates); - UNPROTECT(save); - LEAVE(mixture); - return res; - } else { - validateLastAlloc(); - // Otherwise, the error state is used after its reference count has been incremented - TpmcPattern *errorPattern = - makeNamedWildcardPattern(N->entries[0]->path); - PROTECT(errorPattern); - TpmcArc *errorArc = makeTpmcArc(errorState, errorPattern); - PROTECT(errorArc); - pushTpmcArcArray(state->state->val.test->arcs, errorArc); - TpmcState *res = deduplicateState(state, knownStates); - UNPROTECT(save); - LEAVE(mixture); - return res; - } + TpmcState *res = deduplicateState(testState, knownStates); + UNPROTECT(save); + LEAVE(mixture); + return res; } -TpmcState *tpmcMatch(TpmcMatrix *matrix, TpmcStateArray *finalStates, - TpmcState *errorState, TpmcStateArray *knownStates) { +static TpmcState *match(TpmcMatrix *matrix, TpmcStateArray *finalStates, + TpmcState *errorState, TpmcStateArray *knownStates) { ENTER(match); IFDEBUG(ppTpmcMatrix(matrix)); IFDEBUG(ppTpmcStateArray(finalStates)); @@ -694,11 +683,9 @@ TpmcState *tpmcMatch(TpmcMatrix *matrix, TpmcStateArray *finalStates, cant_happen("zero-height matrix passed to match"); } TpmcState *res = NULL; - if (noRemainingTests(matrix)) { - DEBUG("match: variable rule applies"); + if (topRowOnlyVariables(matrix)) { res = finalStates->entries[0]; } else { - DEBUG("match: mixture rule applies"); res = mixture(matrix, finalStates, errorState, knownStates); } IFDEBUG(ppTpmcState(res)); diff --git a/src/tpmc_mermaid.c b/src/tpmc_mermaid.c index 272c9c9..ced720d 100644 --- a/src/tpmc_mermaid.c +++ b/src/tpmc_mermaid.c @@ -26,12 +26,19 @@ int tpmc_mermaid_flag = 0; static char *mermaidState(TpmcState *state); static void mermaidPattern(TpmcPattern *pattern); +static TpmcVariableTable *seen = NULL; + +static int initSeenTable() { + seen = newTpmcVariableTable(); + return PROTECT(seen); +} + +static void terminateSeenTable(int save) { + UNPROTECT(save); + seen = NULL; +} + static bool seenName(char *name) { - static TpmcVariableTable *seen = NULL; - if (seen == NULL) { - seen = newTpmcVariableTable(); - PROTECT(seen); - } HashSymbol *symbol = newSymbol(name); if (getTpmcVariableTable(seen, symbol)) return true; @@ -39,14 +46,33 @@ static bool seenName(char *name) { return false; } +static void mermaidFreeVariables(TpmcVariableTable *freeVariables) { + printf("["); + if (freeVariables != NULL) { + int i = 0; + int count = 0; + HashSymbol *key; + while ((key = iterateTpmcVariableTable(freeVariables, &i)) != NULL) { + printf("%s", key->name); + count++; + if (count < countTpmcVariableTable(freeVariables)) { + printf(" "); + } + } + } + printf("]"); +} + static char *mermaidStateName(TpmcState *state) { static char buf[512]; switch (state->state->type) { case TPMCSTATEVALUE_TYPE_TEST: sprintf(buf, "T%d", state->stamp); if (!seenName(buf)) { - printf("%s(\"%s\")\n", buf, + printf("%s(\"%s\\n", buf, state->state->val.test->path->name); + mermaidFreeVariables(state->freeVariables); + printf("\")\n"); } break; case TPMCSTATEVALUE_TYPE_FINAL: @@ -54,6 +80,8 @@ static char *mermaidStateName(TpmcState *state) { if (!seenName(buf)) { printf("%s(\"", buf); ppLamExp(state->state->val.final->action); + printf("\\n"); + mermaidFreeVariables(state->freeVariables); printf("\")\n"); } break; @@ -115,6 +143,8 @@ static void mermaidPattern(TpmcPattern *pattern) { static void mermaidArcLabel(TpmcArc *arc) { printf("\""); mermaidPattern(arc->test); + printf("\\n"); + mermaidFreeVariables(arc->freeVariables); printf("\""); } @@ -132,16 +162,6 @@ static void mermaidTestState(char *name, TpmcTestState *testState) { } } -static void mermaidFinalState(char *name - __attribute__((unused)), - TpmcFinalState *finalState - __attribute__((unused))) { - -} - -static void mermaidErrorState(char *name __attribute__((unused))) { -} - static void mermaidStateValue(char *name, TpmcStateValue *value) { if (value == NULL) { return; @@ -151,10 +171,7 @@ static void mermaidStateValue(char *name, TpmcStateValue *value) { mermaidTestState(name, value->val.test); break; case TPMCSTATEVALUE_TYPE_FINAL: - mermaidFinalState(name, value->val.final); - break; case TPMCSTATEVALUE_TYPE_ERROR: - mermaidErrorState(name); break; default: cant_happen @@ -174,10 +191,11 @@ static char *mermaidState(TpmcState *state) { void tpmcMermaid(TpmcState *state) { if (tpmc_mermaid_flag) { - printf("## %p\n", state); + int save = initSeenTable(); printf("```mermaid\n"); printf("flowchart TD\n"); free(mermaidState(state)); printf("```\n"); + terminateSeenTable(save); } } diff --git a/src/tpmc_pp.c b/src/tpmc_pp.c index 1e31331..edb7fe4 100644 --- a/src/tpmc_pp.c +++ b/src/tpmc_pp.c @@ -85,12 +85,15 @@ void ppTpmcPattern(TpmcPattern *pattern) { return; } if (pattern->path == NULL) { - eprintf("=("); + eprintf(""); } else { - eprintf("%s=(", pattern->path->name); + eprintf("%s", pattern->path->name); + } + if (pattern->pattern->type != TPMCPATTERNVALUE_TYPE_WILDCARD) { + eprintf("=("); + ppTpmcPatternValue(pattern->pattern); + eprintf(")"); } - ppTpmcPatternValue(pattern->pattern); - eprintf(")"); } void ppTpmcMatrix(TpmcMatrix *matrix) { diff --git a/src/tpmc_translate.c b/src/tpmc_translate.c index c2e27e7..ea87c4b 100644 --- a/src/tpmc_translate.c +++ b/src/tpmc_translate.c @@ -152,11 +152,13 @@ static LamExp *storeLambdaAndTranslateToApply(TpmcState *dfa, static LamExp *translateComparisonArcToTest(TpmcArc *arc) { ENTER(translateComparisonArcToTest); +#ifdef SAFETY_CHECKS if (arc->test->pattern->type != TPMCPATTERNVALUE_TYPE_COMPARISON) { cant_happen - ("translateComparisonArcToTest ecncountered non-comparison type %d", + ("translateComparisonArcToTest encountered non-comparison type %d", arc->test->pattern->type); } +#endif TpmcComparisonPattern *pattern = arc->test->pattern->val.comparison; LamExp *a = newLamExp(LAMEXP_TYPE_VAR, LAMEXP_VAL_VAR(pattern->previous->path)); @@ -179,19 +181,25 @@ static LamExp *prependLetBindings(TpmcPattern *test, TpmcVariableTable *freeVariables, LamExp *body) { ENTER(prependLetBindings); +#ifdef SAFETY_CHECKS if (test->pattern->type != TPMCPATTERNVALUE_TYPE_CONSTRUCTOR) { cant_happen("prependLetBindings passed non-constructor %d", test->pattern->type); } +#endif TpmcConstructorPattern *constructor = test->pattern->val.constructor; if (constructor->components->size == 0) { + LEAVE(prependLetBindings); return body; } HashSymbol *name = constructor->info->type->name; int save = PROTECT(body); + DEBUG("constructor %s has size %d", name->name, constructor->components->size); for (int i = 0; i < constructor->components->size; i++) { HashSymbol *path = constructor->components->entries[i]->path; + DEBUG("considering variable %s", path->name); if (getTpmcVariableTable(freeVariables, path)) { + DEBUG("%s is free", path->name); LamExp *base = newLamExp(LAMEXP_TYPE_VAR, LAMEXP_VAL_VAR(test->path)); int save2 = PROTECT(base); @@ -208,6 +216,8 @@ static LamExp *prependLetBindings(TpmcPattern *test, body = newLamExp(LAMEXP_TYPE_LET, LAMEXP_VAL_LET(let)); REPLACE_PROTECT(save, body); UNPROTECT(save2); + } else { + DEBUG("%s is not free", path->name); } } LEAVE(prependLetBindings); @@ -367,9 +377,11 @@ static LamExp *translateComparisonArcListToIf(TpmcArcList *arcList, static LamExp *translateArcList(TpmcArcList *arcList, LamExp *testVar, LamExpTable *lambdaCache) { ENTER(translateArcList); +#ifdef SAFETY_CHECKS if (arcList == NULL) { cant_happen("ran out of arcs in translateArcList"); } +#endif LamExp *res = NULL; switch (arcList->arc->test->pattern->type) { case TPMCPATTERNVALUE_TYPE_COMPARISON:{ @@ -487,9 +499,11 @@ static LamIntCondCases *translateConstantIntArcList(TpmcArcList *arcList, LamExp *testVar, LamExpTable *lambdaCache) { +#ifdef SAFETY_CHECKS if (arcList == NULL) { cant_happen("ran out of arcs in translateConstantIntArcList"); } +#endif ENTER(translateConstantIntArcList); LamIntCondCases *res = NULL; switch (arcList->arc->test->pattern->type) { @@ -534,9 +548,11 @@ static LamCharCondCases *translateConstantCharArcList(TpmcArcList *arcList, LamExp *testVar, LamExpTable *lambdaCache) { +#ifdef SAFETY_CHECKS if (arcList == NULL) { cant_happen("ran out of arcs in translateConstantCharArcList"); } +#endif ENTER(translateConstantCharArcList); LamCharCondCases *res = NULL; switch (arcList->arc->test->pattern->type) { @@ -584,15 +600,18 @@ static LamMatchList *translateConstructorArcList(TpmcArcList *arcList, ENTER(translateConstructorArcList); if (arcList == NULL) { if (unexhaustedIndices == NULL) { + LEAVE(translateConstructorArcList); return NULL; } else { cant_happen ("ran out of arcs with unexhausted indices in translateConstructorArcList"); } } +#ifdef SAFETY_CHECKS if (unexhaustedIndices == NULL) { cant_happen("all indices exhausted with arcs remaining"); } +#endif LamMatchList *res = NULL; switch (arcList->arc->test->pattern->type) { case TPMCPATTERNVALUE_TYPE_COMPARISON:{ From 6ab799dd745eb9c67330d62d451c496104981e9c Mon Sep 17 00:00:00 2001 From: Bill Hails Date: Sat, 30 Mar 2024 17:07:13 +0000 Subject: [PATCH 29/33] code generation of TypeName functions for debugging --- src/tpmc_match.c | 16 ++++++++-------- tools/makeAST.py | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 8 deletions(-) diff --git a/src/tpmc_match.c b/src/tpmc_match.c index 4a6bd1e..22cb52f 100644 --- a/src/tpmc_match.c +++ b/src/tpmc_match.c @@ -127,8 +127,8 @@ static bool patternMatches(TpmcPattern *constructor, TpmcPattern *pattern) { return res; } default: - cant_happen("unrecognized pattern type %d in patternMatches", - pattern->pattern->type); + cant_happen("unrecognized pattern type %s in patternMatches", + tpmcPatternValueTypeName(pattern->pattern->type)); } } @@ -322,8 +322,8 @@ static TpmcMatrix *makeSubPatternMatrix(TpmcPatternArray *patterns, int arity) { ("encountered pattern type int during makeSubPatternMatrix"); default: cant_happen - ("unrecognised pattern type %d during makeSubPatternMatrix", - pattern->pattern->type); + ("unrecognised pattern type %s during makeSubPatternMatrix", + tpmcPatternValueTypeName(pattern->pattern->type)); } } UNPROTECT(save); @@ -478,8 +478,8 @@ static void collectPathsBoundByPattern(TpmcPattern *pattern, } break; default: - cant_happen("unrecognised type %d in collectPathsBoundByPattern", - pattern->pattern->type); + cant_happen("unrecognised type %s in collectPathsBoundByPattern", + tpmcPatternValueTypeName(pattern->pattern->type)); } } @@ -529,8 +529,8 @@ static TpmcVariableTable *getStatesFreeVariables(TpmcState *state) { ("getStatesFreeVariables encountered error state with null free variables"); default: cant_happen - ("unrecognised state type %d in getStateFreeVariables", - state->state->type); + ("unrecognised state type %s in getStateFreeVariables", + tpmcStateValueTypeName(state->state->type)); } } return state->freeVariables; diff --git a/tools/makeAST.py b/tools/makeAST.py index a7d9d05..2996ca0 100644 --- a/tools/makeAST.py +++ b/tools/makeAST.py @@ -141,6 +141,14 @@ def printCopyDeclarations(self): for entity in self.contents.values(): entity.printCopyDeclaration(self) + def printNameFunctionDeclarations(self): + for entity in self.contents.values(): + entity.printNameFunctionDeclaration() + + def printNameFunctionBodies(self): + for entity in self.contents.values(): + entity.printNameFunctionBody() + def printPrintFunctions(self): for entity in self.contents.values(): entity.printPrintFunction(self) @@ -262,6 +270,12 @@ def build(self, catalog): def printTypedef(self, catalog): pass + def printNameFunctionDeclaration(self): + pass + + def printNameFunctionBody(self): + pass + def printFreeDeclaration(self, catalog): pass @@ -392,6 +406,10 @@ def printEnumTypedefLine(self, count): field = self.makeTypeName() print(f" {field}, // {count}"); + def printNameFunctionLine(self): + field = self.makeTypeName() + print(f' case {field}: return "{field}";') + def makeTypeName(self): v = self.owner + '_type_' + self.name v = v.upper().replace('AST', 'AST_') @@ -1736,6 +1754,30 @@ def getName(self): def getFieldName(self): return 'type' + def getNameFunctionDeclaration(self): + name = self.getName(); + camel = name[0].lower() + name[1:] + return f"char * {camel}Name(enum {name} type)" + + def printNameFunctionDeclaration(self): + decl = self.getNameFunctionDeclaration() + print(f"{decl}; // DiscriminatedUnionEnum.printNameFunctionDeclaration") + + def printNameFunctionBody(self): + decl = self.getNameFunctionDeclaration() + print(f"{decl} {{ // DiscriminatedUnionEnum.printNameFunctionDeclaration") + print(" switch(type) {") + for field in self.fields: + field.printNameFunctionLine() + print(" default: {") + print(" static char buf[64];") + print(' sprintf(buf, "%d", type);') + print(" return buf;"); + print(" }") + print(" }") + print("}") + print("") + def getTypeDeclaration(self): return "enum {name} ".format(name=self.getName()) @@ -2003,6 +2045,8 @@ def printSection(name): catalog.printAccessDeclarations() printSection("count declarations") catalog.printCountDeclarations() + printSection("name declarations") + catalog.printNameFunctionDeclarations() print("") print("#endif") @@ -2057,6 +2101,8 @@ def printSection(name): catalog.printFreeObjFunction() printSection("type identifier function") catalog.printTypeObjFunction() + printSection("type name function") + catalog.printNameFunctionBodies() elif args.type == 'debug_h': From e68deda7e8fd92f16cf99f7168a301ef6f1350d7 Mon Sep 17 00:00:00 2001 From: Bill Hails Date: Sun, 31 Mar 2024 11:06:24 +0100 Subject: [PATCH 30/33] TPMC now supports comparison --- docs/lambda-conversion.md | 114 +++++++++++++++++++++++++++++++++----- src/common.h | 4 +- src/lambda_conversion.c | 12 +++- src/main.c | 14 +++-- src/tpmc_match.c | 4 +- src/tpmc_mermaid.c | 2 + src/tpmc_mermaid.h | 3 + 7 files changed, 129 insertions(+), 24 deletions(-) diff --git a/docs/lambda-conversion.md b/docs/lambda-conversion.md index e8ce4ee..1b348f2 100644 --- a/docs/lambda-conversion.md +++ b/docs/lambda-conversion.md @@ -683,7 +683,27 @@ in undefined variable p$15$0 in analyzeVar ``` -The intermediate code generated is +The DFA constructed is + +```mermaid +flowchart TD +T39("p$16\n[]") +F36("(begin 1)\n[p$16]") +T39 --"p$16:p$15:_==p$16:_\n[p$15]"--> F36 +T40("p$15\n[p$16 p$15]") +F37("(begin 2)\n[p$16]") +T40 --"p$15:bar(p$15$0:_)\n[p$16]"--> F37 +ERROR +T40 --"p$15:_\n[]"--> ERROR +T39 --"p$16:p$15$0:_==p$16:_\n[p$15$0 p$15]"--> T40 +ERROR +T39 --"p$16:_\n[]"--> ERROR +``` + +(`cekf --tpmc-mermaid` will generate the above diagram) + +And the intermediate code generated is + ```scheme (lambda (p$15 p$16) (letrec (($tpmc38 (lambda () (error)))) @@ -696,28 +716,96 @@ The intermediate code generated is ($tpmc38))))) ``` -So walking through, the matrix will be +So walking through, the matrix M and final states S will be + +| M1 | M2 | S | +| ------------------- | --------------- | ----------- | +| `p$15` | `p$16==p$15` | `(begin 1)` | +| `p$15=bar(p$15$0)` | `p$16==p$15$0` | `(begin 2)` | + -``` -(p$15, p$16==p$15) -(p$15=bar(p$15$0), p$16==p$15$0) The mixture rule applies on row 1 column 2 because it is a comparison not just a var. -N is +So The algorithm finds two constructors in column 2, both are distict +comparisons so don't match one another. -``` -p$16==p$15 -p$16==p$15$0 +Construction of the first arc for Row 1 compiles fine, match recurses +on `p$15` where the variable rule applies and the final state `1` is +returned, then an arc from the start state to the first final state is +constructed, labelled by the comparison: + +```mermaid +flowchart LR +T39("p$16\n[]") +F36("(begin 1)\n[p$16]") +T39 --"p$16:p$15:_==p$16:_\n[p$15]"--> F36 ``` -M-N is +The reason this compiles ok is that `p$15` (the first `x` in of the +source function) is bound by the top-level function before the comparison +is done. +The free variable `[p$15]` on the arc is because of an earlier attempt +to fix the issue, it wouldn't be there in the vanilla implementation. + +Anyway the problem occurs when compiling the second row of the matrix. +Match recurses on `p$15=bar(p$15$0)` where the mixture rule applies, +eventually resulting in an intermediate test state and arc to the final +state labelled with the constructor: + +```mermaid +flowchart LR +T41("p$15\n[p$16 p$15]") +F37("(begin 2)\n[p$16]") +T41 --"p$15:bar(p$15$0:_)\n[p$16]"--> F37 ``` -(p$15 ) -(p$15=bar(p$15$0)) + +and `mixture` then prepends this with an arc from the start state, +labelled with the comparison: + +```mermaid +flowchart LR +T40("p$16\n[]") +T41("p$15\n[p$16 p$15]") +F37("(begin 2)\n[p$16]") +T41 --"p$15:bar(p$15$0:_)\n[p$16]"--> F37 +T40 --"p$16:p$15$0:_==p$16:_\n[p$15$0 p$15]"--> T41 ``` -both rows match so the indices are {1, 2} +The problem is that when the intermediate code is generated, `p$15$0` +is free (not yet bound by the second match) at the time the comparison +code is emitted. + +To summarise, the algorithm given the initial matrix skips past the +plain var `x` in row 1 to find column 2, which in turn results in row +2 column 2 being processed before row 2 column 1. + +### Possible Solutions + +One possibility, extend the algorithm so that after identifying column +2 in the above, it finally decides to process column 1 instead, because +it sees the depenancy of row 2 column 2 on row 2 column 1. In fact could +it just say "because there is a pattern in the first row, process the +first column"? I suspect not, there are potentially no constructors +in column 1, but would that be a problem? Very easy to try out and it +seems to work! The generated DFA for `fail` has one extra state, so maybe +it's less optimised, but all tests still pass and fail now works! +```mermaid +flowchart TD +T40("p$15\n[]") +T41("p$16\n[p$16 p$15$0 p$15]") +F36("(begin 1)\n[p$16]") +T41 --"p$16:p$15:_==p$16:_\n[p$15]"--> F36 +F37("(begin 2)\n[p$16]") +T41 --"p$16:p$15$0:_==p$16:_\n[p$15$0]"--> F37 +F38("(begin 3)\n[]") +T41 --"p$16:_\n[]"--> F38 +T40 --"p$15:bar(p$15$0:_)\n[p$16]"--> T41 +T42("p$16\n[p$16 p$15]") +T42 --"p$16:p$15:_==p$16:_\n[p$15]"--> F36 +T42 --"p$16:_\n[]"--> F38 +T40 --"p$15:_\n[p$16]"--> T42 +``` diff --git a/src/common.h b/src/common.h index 0411cd4..8af2700 100644 --- a/src/common.h +++ b/src/common.h @@ -33,9 +33,9 @@ # define DEBUG_STRESS_GC // #define DEBUG_LOG_GC // #define DEBUG_GC -# define DEBUG_TPMC_MATCH +// # define DEBUG_TPMC_MATCH // # define DEBUG_TPMC_TRANSLATE -# define DEBUG_TPMC_LOGIC +// # define DEBUG_TPMC_LOGIC // #define DEBUG_ANNOTATE // #define DEBUG_DESUGARING // #define DEBUG_HASHTABLE diff --git a/src/lambda_conversion.c b/src/lambda_conversion.c index 5317b74..374cc2e 100644 --- a/src/lambda_conversion.c +++ b/src/lambda_conversion.c @@ -28,6 +28,7 @@ #include "lambda_helper.h" #include "symbols.h" #include "tpmc_logic.h" +#include "tpmc_mermaid.h" #include "ast_debug.h" #include "print_generator.h" @@ -400,10 +401,17 @@ static LamExp *makeConstant(HashSymbol *name, int tag) { return res; } -static LamLetRecBindings *prependDefine(AstDefine *define, LamContext *env, - LamLetRecBindings *next) { +static LamLetRecBindings *prependDefine(AstDefine * define, LamContext * env, + LamLetRecBindings * next) { ENTER(prependDefine); + bool doMermaid = (tpmc_mermaid_function != NULL + && strcmp(tpmc_mermaid_function, + define->symbol->name) == 0); + if (doMermaid) + tpmc_mermaid_flag = 1; LamExp *exp = convertExpression(define->expression, env); + if (doMermaid) + tpmc_mermaid_flag = 0; int save = PROTECT(exp); LamLetRecBindings *this = newLamLetRecBindings(dollarSubstitute(define->symbol), exp, next); diff --git a/src/main.c b/src/main.c index e664a96..9b3391c 100644 --- a/src/main.c +++ b/src/main.c @@ -54,8 +54,8 @@ static void processArgs(int argc, char *argv[]) { static struct option long_options[] = { { "bigint", no_argument, &bigint_flag, 1 }, { "report", no_argument, &report_flag, 1 }, - { "tpmc-mermaid", no_argument, &tpmc_mermaid_flag, 1 }, { "help", no_argument, &help_flag, 1 }, + { "tpmc-mermaid", required_argument, 0, 'm' }, { 0, 0, 0, 0 } }; int option_index = 0; @@ -64,14 +64,18 @@ static void processArgs(int argc, char *argv[]) { if (c == -1) break; + + if (c == 'm') { + tpmc_mermaid_function = optarg; + } } if (help_flag) { printf("%s", - "--bigint use arbitrary precision integers\n" - "--report report statistics\n" - "--tpmc-mermaid produce a mermaid graph of each TPMC state table\n" - "--help this help\n"); + "--bigint use arbitrary precision integers\n" + "--report report statistics\n" + "--tpmc-mermaid=function produce a mermaid graph of the function's TPMC state table\n" + "--help this help\n"); exit(0); } diff --git a/src/tpmc_match.c b/src/tpmc_match.c index 22cb52f..e27f7a9 100644 --- a/src/tpmc_match.c +++ b/src/tpmc_match.c @@ -409,8 +409,7 @@ static bool arcsAreExhaustive(int size, TpmcArcArray *arcs) { static bool constructorsAreExhaustive(TpmcState *state) { TpmcTestState *testState = state->state->val.test; if (testState->arcs->size == 0) { - cant_happen - ("constructorsAreExhaustive() passed a test state with zero arcs"); + return false; } TpmcPattern *pattern = testState->arcs->entries[0]->test; if (pattern->pattern->type == TPMCPATTERNVALUE_TYPE_WILDCARD) { @@ -585,6 +584,7 @@ static TpmcState *mixture(TpmcMatrix *M, TpmcStateArray *finalStates, ENTER(mixture); // there is some column N whose topmost pattern is a constructor int firstConstructorColumn = findFirstConstructorColumn(M); + firstConstructorColumn = 0; TpmcPatternArray *N = extractMatrixColumn(firstConstructorColumn, M); int save = PROTECT(N); // let M-N be all the columns in M except N diff --git a/src/tpmc_mermaid.c b/src/tpmc_mermaid.c index ced720d..a0a3337 100644 --- a/src/tpmc_mermaid.c +++ b/src/tpmc_mermaid.c @@ -22,6 +22,7 @@ #include "tpmc_mermaid.h" int tpmc_mermaid_flag = 0; +char *tpmc_mermaid_function = NULL; static char *mermaidState(TpmcState *state); static void mermaidPattern(TpmcPattern *pattern); @@ -192,6 +193,7 @@ static char *mermaidState(TpmcState *state) { void tpmcMermaid(TpmcState *state) { if (tpmc_mermaid_flag) { int save = initSeenTable(); + printf("## %s\n", tpmc_mermaid_function); printf("```mermaid\n"); printf("flowchart TD\n"); free(mermaidState(state)); diff --git a/src/tpmc_mermaid.h b/src/tpmc_mermaid.h index 94afcc6..22511f8 100644 --- a/src/tpmc_mermaid.h +++ b/src/tpmc_mermaid.h @@ -23,4 +23,7 @@ void tpmcMermaid(TpmcState *state); extern int tpmc_mermaid_flag; + +extern char *tpmc_mermaid_function; + #endif From 776062b95ac322f3a4937d042e752747b41a4bfc Mon Sep 17 00:00:00 2001 From: Bill Hails Date: Sun, 31 Mar 2024 13:32:59 +0100 Subject: [PATCH 31/33] print now appends newline --- fn/derivative.fn | 43 ++++++++++++++++++++++++++++++++++- fn/derivative2.fn | 10 ++++---- src/main.c | 3 ++- src/print_compiler.c | 54 ++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 98 insertions(+), 12 deletions(-) diff --git a/fn/derivative.fn b/fn/derivative.fn index 2f4fadb..713d9f5 100644 --- a/fn/derivative.fn +++ b/fn/derivative.fn @@ -6,15 +6,56 @@ let mul(term, term) | div(term, term) | pow(term, term) } + fn deriv { (x, x) { num(1) } (num(_), _) { num(0) } (pow(x, num(n)), x) { mul(num(n), pow(x, num(n - 1))) } + (pow(y, n), x) { + let t = simplify(y); + in + if (t == y) { + pow(t, n) + } else { + deriv(pow(t, n), x) + } + } (add(f, g), x) { add(deriv(f, x), deriv(g, x)) } (sub(f, g), x) { sub(deriv(f, x), deriv(g, x)) } (mul(f, g), x) { add(mul(g, deriv(f, x)), mul(f, deriv(g, x))) } (div(num(1), f), x) { div(sub(num(0), deriv(f, x)), mul(f, f)) } (div(f, g), x) { div(sub(mul(g, deriv(f, x)), mul(f, deriv(g, x))), mul(g, g)) } } + + fn simplify { + (x=num(_)) { x } + (x=var(_)) { x } + (add(a, num(0))) | + (add(num(0), a)) { simplify(a) } + (add(num(a), num(b))) { num(a + b) } + (add(num(a), add(num(b), x))) | + (add(num(a), add(x, num(b)))) | + (add(add(x, num(b)), num(a))) | + (add(add(num(b), x), num(a))) { simplify(add(num(a + b), x)) } + (add(a, num(n))) | + (add(a, b)) { add(simplify(a), simplify(b)) } + (sub(a, num(0))) { simplify(a) } + (sub(a, b)) { sub(simplify(a), simplify(b)) } + (mul(num(0), _)) | + (mul(_, num(0))) { num(0) } + (mul(num(1), a)) | + (mul(a, num(1))) { simplify(a) } + (mul(num(a), num(b))) { num(a * b) } + (mul(a, b)) { mul(simplify(a), simplify(b)) } + (div(a, num(1))) { simplify(a) } + (div(num(0), a)) { num(0) } + (div(a, b)) { div(simplify(a), simplify(b)) } + (pow(a, num(1))) { simplify(a) } + (pow(a, num(0))) { num(1) } + (pow(num(a), num(b))) { num(a**b) } + // (a + b)**2 == a**2 + 2ab + b**2 + (pow(add(a, b), num(2))) { simplify(add(pow(a, num(2)), add(mul(num(2), mul(a, b)), pow(b, num(2))))) } + (pow(a, b)) { pow(simplify(a), simplify(b)) } + } in - print(deriv(add(add(pow(var('x'), num(2)), var('x')), num(1)), var('x'))) + print(simplify(deriv(add(add(pow(add(var('x'), num(1)), num(2)), var('x')), num(1)), var('x')))) diff --git a/fn/derivative2.fn b/fn/derivative2.fn index c2d6512..fcc866e 100644 --- a/fn/derivative2.fn +++ b/fn/derivative2.fn @@ -13,13 +13,13 @@ let } else { switch(t) { (num(_)) { num(0) } - (pow(x1, num(n))) { - if (x1 == x) { - mul(num(n), pow(x1, num(n - 1))) + (pow(y, num(n))) { + if (y == x) { + mul(num(n), pow(y, num(n - 1))) } else { - let t = simplify(x1); + let t = simplify(y); in - if (t == x1) { + if (t == y) { pow(t, num(n)) } else { deriv(pow(t, num(n)), x) diff --git a/src/main.c b/src/main.c index 9b3391c..c211119 100644 --- a/src/main.c +++ b/src/main.c @@ -74,7 +74,8 @@ static void processArgs(int argc, char *argv[]) { printf("%s", "--bigint use arbitrary precision integers\n" "--report report statistics\n" - "--tpmc-mermaid=function produce a mermaid graph of the function's TPMC state table\n" + "--tpmc-mermaid=function produce a mermaid graph of the\n" + " function's TPMC state table\n" "--help this help\n"); exit(0); } diff --git a/src/print_compiler.c b/src/print_compiler.c index 2d8f6a6..8320e29 100644 --- a/src/print_compiler.c +++ b/src/print_compiler.c @@ -42,9 +42,53 @@ static LamExp *compilePrinterForVar(TcVar *var, TcEnv *env); static LamExp *compilePrinterForInt(); static LamExp *compilePrinterForChar(); static LamExp *compilePrinterForUserType(TcUserType *userType, TcEnv *env); +static LamExp *compilePrinter(TcType *type, TcEnv *env); LamExp *compilePrinterForType(TcType *type, TcEnv *env) { - ENTER(compilePrinterForType); + // (lambda (x) (begin (printer x) (putc '\n') x) + LamExp *printer = compilePrinter(type, env); + int save = PROTECT(printer); + // x) + HashSymbol *name = genSym("x$"); + LamExp *var = newLamExp(LAMEXP_TYPE_VAR, LAMEXP_VAL_VAR(name)); + PROTECT(var); + LamSequence *seq = newLamSequence(var, NULL); + PROTECT(seq); + + // (putc '\n') x) + LamExp *newline = newLamExp(LAMEXP_TYPE_CHARACTER, LAMEXP_VAL_CHARACTER('\n')); + PROTECT(newline); + LamUnaryApp *app = newLamUnaryApp(LAMUNARYOP_TYPE_PUTC, newline); + PROTECT(app); + LamExp *exp = newLamExp(LAMEXP_TYPE_UNARY, LAMEXP_VAL_UNARY(app)); + PROTECT(exp); + seq = newLamSequence(exp, seq); + PROTECT(seq); + + // (printer x) (putc '\n') x) + LamList *args = newLamList(var, NULL); + PROTECT(args); + LamApply *apply = newLamApply(printer, 1, args); + PROTECT(apply); + LamExp *applyExp = newLamExp(LAMEXP_TYPE_APPLY, LAMEXP_VAL_APPLY(apply)); + PROTECT(applyExp); + seq = newLamSequence(applyExp, seq); + PROTECT(seq); + + // (lambda (x) (begin (printer x) (putc '\n') x) + LamVarList *fargs = newLamVarList(name, NULL); + PROTECT(fargs); + LamExp *body = newLamExp(LAMEXP_TYPE_LIST, LAMEXP_VAL_LIST(seq)); + PROTECT(body); + LamLam *lambda = newLamLam(1, fargs, body); + PROTECT(lambda); + LamExp *res = newLamExp(LAMEXP_TYPE_LAM, LAMEXP_VAL_LAM(lambda)); + UNPROTECT(save); + return res; +} + +static LamExp *compilePrinter(TcType *type, TcEnv *env) { + ENTER(compilePrinter); LamExp *res = NULL; switch (type->type) { case TCTYPE_TYPE_FUNCTION: @@ -67,10 +111,10 @@ LamExp *compilePrinterForType(TcType *type, TcEnv *env) { res = compilePrinterForUserType(type->val.userType, env); break; default: - cant_happen("unrecognised TcType %d in compilePrinterForType", + cant_happen("unrecognised TcType %d in compilePrinter", type->type); } - LEAVE(compilePrinterForType); + LEAVE(compilePrinter); return res; } @@ -87,7 +131,7 @@ static LamExp *compilePrinterForVar(TcVar *var, TcEnv *env) { if (var->instance == NULL) { return makeSymbolExpr("print$"); } - return compilePrinterForType(var->instance, env); + return compilePrinter(var->instance, env); } static LamExp *compilePrinterForInt() { @@ -107,7 +151,7 @@ static LamList *compilePrinterForUserTypeArgs(TcUserTypeArgs *args, } LamList *next = compilePrinterForUserTypeArgs(args->next, env); int save = PROTECT(next); - LamExp *this = compilePrinterForType(args->type, env); + LamExp *this = compilePrinter(args->type, env); PROTECT(this); LamList *res = newLamList(this, next); UNPROTECT(save); From 472bf3b69e1758bf22baf740e68afea92108994b Mon Sep 17 00:00:00 2001 From: Bill Hails Date: Sun, 31 Mar 2024 13:49:30 +0100 Subject: [PATCH 32/33] tidy-up after print newline --- fn/barrels.fn | 3 +-- fn/dictionary.fn | 3 +-- fn/fact.fn | 3 +-- fn/interpreter.fn | 3 +-- fn/liars.fn | 3 +-- fn/listutils.fn | 3 +-- fn/oddEven.fn | 3 +-- fn/pythagoreanTriples.fn | 1 - fn/redBlack.fn | 3 +-- 9 files changed, 8 insertions(+), 17 deletions(-) diff --git a/fn/barrels.fn b/fn/barrels.fn index a6f3e2f..5425413 100644 --- a/fn/barrels.fn +++ b/fn/barrels.fn @@ -63,5 +63,4 @@ let beer } in - print(barrels_of_fun()); - puts("\n") + print(barrels_of_fun()) diff --git a/fn/dictionary.fn b/fn/dictionary.fn index 03624fc..79d125f 100644 --- a/fn/dictionary.fn +++ b/fn/dictionary.fn @@ -124,5 +124,4 @@ let } in - print(lookup('f', delete('k', makeDict("kgimtseettepmupybbbmplgntqzutrfxqarki")))); - puts("\n") + print(lookup('f', delete('k', makeDict("kgimtseettepmupybbbmplgntqzutrfxqarki")))) diff --git a/fn/fact.fn b/fn/fact.fn index a925b02..f1c88a4 100644 --- a/fn/fact.fn +++ b/fn/fact.fn @@ -4,5 +4,4 @@ let (n) { n * fact(n - 1) } } in - print(fact(1000)); - puts("\n") + print(fact(1000)) diff --git a/fn/interpreter.fn b/fn/interpreter.fn index 79472ff..9483d69 100644 --- a/fn/interpreter.fn +++ b/fn/interpreter.fn @@ -71,5 +71,4 @@ in symbol("a") ), frame("a", number(3), root) - )); - puts("\n") + )) diff --git a/fn/liars.fn b/fn/liars.fn index d76e37d..a5b47d5 100644 --- a/fn/liars.fn +++ b/fn/liars.fn @@ -44,5 +44,4 @@ let [betty, ethel, joan, kitty, mary] } in - print(liars()); - puts("\n") + print(liars()) diff --git a/fn/listutils.fn b/fn/listutils.fn index f9a94d5..df59056 100644 --- a/fn/listutils.fn +++ b/fn/listutils.fn @@ -182,5 +182,4 @@ let } in - print(concat(take(3, ["well", " ", "hi", " ", "there"]))); - puts("\n") + print(concat(take(3, ["well", " ", "hi", " ", "there"]))) diff --git a/fn/oddEven.fn b/fn/oddEven.fn index 1a704d6..09f9586 100644 --- a/fn/oddEven.fn +++ b/fn/oddEven.fn @@ -8,5 +8,4 @@ let (n) { odd(n - 1) } } in - print(odd(3)); - puts("\n") + print(odd(3)) diff --git a/fn/pythagoreanTriples.fn b/fn/pythagoreanTriples.fn index 8bddcf9..e89d86a 100644 --- a/fn/pythagoreanTriples.fn +++ b/fn/pythagoreanTriples.fn @@ -25,6 +25,5 @@ in { let triple = pythagorean_triples(); in print(triple); - puts("\n"); require( 20) // until } diff --git a/fn/redBlack.fn b/fn/redBlack.fn index fe2f0b8..dd5184f 100644 --- a/fn/redBlack.fn +++ b/fn/redBlack.fn @@ -91,5 +91,4 @@ in "knhonxyxgbgpawkahqbknbqpargbnnunwgxphhlvedlyazkfzavezdtl" "fefpvjiooocpwspyalpahadximvaauocirfgpijbhqskcuuynvcvtndi" "fklhczerlvjpfpjhnkxxprrsktdfnrrmoypigecxbkzxflgtmdxxzfvd" - "vesewzqotfdlqfibzkchndafnmxirrruol"))); - puts("\n") + "vesewzqotfdlqfibzkchndafnmxirrruol"))) From f2d59edc415e6e1815f4343366872d3bc95c8507 Mon Sep 17 00:00:00 2001 From: Bill Hails Date: Sun, 31 Mar 2024 16:30:39 +0100 Subject: [PATCH 33/33] renamed starship to spaceship (old typo propagated) --- docs/TODO.md | 32 ++++++++++++++++---------------- src/symbols.c | 2 +- src/symbols.h | 2 +- src/tc_analyze.c | 12 ++++++------ 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/docs/TODO.md b/docs/TODO.md index f64b19b..9f66385 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -1,30 +1,30 @@ # TODO -* over-application i.e. `fn (a) { fn (b) { a + b } }(2, 3)` -* allow user overrides of print functions +* over-application i.e. `fn (a) { fn (b) { a + b } }(2, 3)`. +* allow user overrides of print functions. * tuples - can use vec type to implement. - * BUT - fn args are not tuples, that might interfere with currying. + * BUT - the collection of args to a function is not itself a tuple, that might interfere with currying. * tc has support for pairs and we might leverage those as a start, but flat vecs will be more efficient. * specific syntax: `#(2, "hi")` might be better than just round braces. -* unpacking function return values (tuples only) +* unpacking function return values (tuples only). * `now()` expression returns current time in milliseconds. * macro support (see [MACROS](./MACROS.md) for initial thoughts). * more numbers: - * rationals: 1/3 - * irrationals: sqrt(2) - * complex numbers -* UTF8 and `wchar_t` -* first class environments -* libraries - * probably use file system layout - * env var to specify the root location(s) - * better preable/postamble handling + * rationals: 1/3. + * irrationals: sqrt(2). + * complex numbers. +* UTF8 and `wchar_t`. +* first class environments. +* libraries. + * probably use file system layout. + * env var to specify the root location(s). + * better preable/postamble handling. * propagate file and line numbers into all error reporting. * much better error reporting. * error recovery. * command-line arguments for libraries etc. * fail on non-exhaustive pattern match (optional). -* error function -* user definable infix operators - * with precedence and associativity +* error function. +* user definable infix operators. + * with precedence and associativity. * curried binary operators `(2+)` etc. diff --git a/src/symbols.c b/src/symbols.c index 5ff192b..6e1a58a 100644 --- a/src/symbols.c +++ b/src/symbols.c @@ -181,7 +181,7 @@ HashSymbol *cmpSymbol() { return res; } -HashSymbol *starshipSymbol() { +HashSymbol *spaceshipSymbol() { static HashSymbol *res = NULL; if (res == NULL) { res = newSymbol("cmp"); diff --git a/src/symbols.h b/src/symbols.h index c87bcfb..c438f0f 100644 --- a/src/symbols.h +++ b/src/symbols.h @@ -45,7 +45,7 @@ HashSymbol *leSymbol(void); HashSymbol *listSymbol(void); HashSymbol *ltSymbol(void); HashSymbol *cmpSymbol(void); -HashSymbol *starshipSymbol(void); +HashSymbol *spaceshipSymbol(void); HashSymbol *modSymbol(void); HashSymbol *mulSymbol(void); HashSymbol *negSymbol(void); diff --git a/src/tc_analyze.c b/src/tc_analyze.c index 3b00a14..e62cc7e 100644 --- a/src/tc_analyze.c +++ b/src/tc_analyze.c @@ -42,7 +42,7 @@ static void addToNg(TcNg *env, TcType *type); static void addFreshVarToEnv(TcEnv *env, HashSymbol *key); static void addCmpToEnv(TcEnv *env, HashSymbol *key); static TcType *makeBoolean(void); -static TcType *makeStarship(void); +static TcType *makeSpaceship(void); static TcType *makeSmallInteger(void); static TcType *makeBigInteger(void); static TcType *makeCharacter(void); @@ -303,7 +303,7 @@ static TcType *analyzeComparison(LamExp *exp1, LamExp *exp2, TcEnv *env, return res; } -static TcType *analyzeStarship(LamExp *exp1, LamExp *exp2, TcEnv *env, +static TcType *analyzeSpaceship(LamExp *exp1, LamExp *exp2, TcEnv *env, TcNg *ng) { // ENTER(analyzeComparison); TcType *type1 = analyzeExp(exp1, env, ng); @@ -318,7 +318,7 @@ static TcType *analyzeStarship(LamExp *exp1, LamExp *exp2, TcEnv *env, eprintf("\n"); } UNPROTECT(save); - TcType *res = makeStarship(); + TcType *res = makeSpaceship(); // LEAVE(analyzeComparison); return res; } @@ -367,7 +367,7 @@ static TcType *analyzePrim(LamPrimApp *app, TcEnv *env, TcNg *ng) { res = analyzeComparison(app->exp1, app->exp2, env, ng); break; case LAMPRIMOP_TYPE_CMP: - res = analyzeStarship(app->exp1, app->exp2, env, ng); + res = analyzeSpaceship(app->exp1, app->exp2, env, ng); break; case LAMPRIMOP_TYPE_VEC: cant_happen("encountered VEC in analyzePrim"); @@ -1297,8 +1297,8 @@ static TcType *makeBoolean() { return res; } -static TcType *makeStarship() { - TcType *res = makeUserType(starshipSymbol(), NULL); +static TcType *makeSpaceship() { + TcType *res = makeUserType(spaceshipSymbol(), NULL); return res; }