mirror of
https://github.com/GrammaticalFramework/gf-core.git
synced 2026-04-22 11:19:32 -06:00
initial import of the C runtime
This commit is contained in:
251
src/runtime/c/pgf/data.c
Normal file
251
src/runtime/c/pgf/data.c
Normal file
@@ -0,0 +1,251 @@
|
||||
#include "data.h"
|
||||
#include "expr.h"
|
||||
#include <gu/type.h>
|
||||
#include <gu/variant.h>
|
||||
#include <gu/assert.h>
|
||||
|
||||
|
||||
PgfCCat pgf_ccat_string = { NULL, GU_NULL_SEQ, -1 };
|
||||
PgfCCat pgf_ccat_int = { NULL, GU_NULL_SEQ, -2 };
|
||||
PgfCCat pgf_ccat_float = { NULL, GU_NULL_SEQ, -3 };
|
||||
PgfCCat pgf_ccat_var = { NULL, GU_NULL_SEQ, -4 };
|
||||
|
||||
PgfCCatId
|
||||
pgf_literal_cat(PgfLiteral lit)
|
||||
{
|
||||
switch (gu_variant_tag(lit)) {
|
||||
case PGF_LITERAL_STR:
|
||||
return &pgf_ccat_string;
|
||||
case PGF_LITERAL_INT:
|
||||
return &pgf_ccat_int;
|
||||
case PGF_LITERAL_FLT:
|
||||
return &pgf_ccat_float;
|
||||
default:
|
||||
gu_impossible();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
pgf_tokens_equal(PgfTokens t1, PgfTokens t2)
|
||||
{
|
||||
size_t len1 = gu_seq_length(t1);
|
||||
size_t len2 = gu_seq_length(t2);
|
||||
if (len1 != len2) {
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < len1; i++) {
|
||||
GuString s1 = gu_seq_get(t1, PgfToken, i);
|
||||
GuString s2 = gu_seq_get(t2, PgfToken, i);
|
||||
if (!gu_string_eq(s1, s2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GU_DEFINE_TYPE(PgfTokens, GuSeq, gu_type(GuString));
|
||||
|
||||
GU_DEFINE_TYPE(PgfCId, typedef, gu_type(GuString));
|
||||
|
||||
GU_DEFINE_TYPE(GuStringL, GuList, gu_type(GuString));
|
||||
|
||||
|
||||
#define gu_type__PgfCIdMap gu_type__GuStringMap
|
||||
typedef GuType_GuStringMap GuType_PgfCIdMap;
|
||||
#define GU_TYPE_INIT_PgfCIdMap GU_TYPE_INIT_GuStringMap
|
||||
|
||||
GU_DEFINE_TYPE(PgfCCat, struct,
|
||||
GU_MEMBER_S(PgfCCat, cnccat, PgfCncCat),
|
||||
GU_MEMBER(PgfCCat, prods, PgfProductionSeq));
|
||||
|
||||
GU_DEFINE_TYPE(PgfCCatId, shared, gu_type(PgfCCat));
|
||||
|
||||
GU_DEFINE_TYPE(PgfCCatIds, GuList, gu_type(PgfCCatId));
|
||||
|
||||
GU_DEFINE_TYPE(PgfCCatSeq, GuSeq, gu_type(PgfCCatId));
|
||||
|
||||
GU_DEFINE_TYPE(PgfAlternative, struct,
|
||||
GU_MEMBER(PgfAlternative, form, PgfTokens),
|
||||
GU_MEMBER_P(PgfAlternative, prefixes, GuStringL));
|
||||
|
||||
|
||||
GU_DEFINE_TYPE(
|
||||
PgfSymbol, GuVariant,
|
||||
GU_CONSTRUCTOR_S(
|
||||
PGF_SYMBOL_CAT, PgfSymbolCat,
|
||||
GU_MEMBER(PgfSymbolCat, d, int),
|
||||
GU_MEMBER(PgfSymbolCat, r, int)),
|
||||
GU_CONSTRUCTOR_S(
|
||||
PGF_SYMBOL_LIT, PgfSymbolLit,
|
||||
GU_MEMBER(PgfSymbolLit, d, int),
|
||||
GU_MEMBER(PgfSymbolLit, r, int)),
|
||||
GU_CONSTRUCTOR_S(
|
||||
PGF_SYMBOL_VAR, PgfSymbolVar,
|
||||
GU_MEMBER(PgfSymbolVar, d, int),
|
||||
GU_MEMBER(PgfSymbolVar, r, int)),
|
||||
GU_CONSTRUCTOR_S(
|
||||
PGF_SYMBOL_KS, PgfSymbolKS,
|
||||
GU_MEMBER(PgfSymbolKS, tokens, PgfTokens)),
|
||||
GU_CONSTRUCTOR_S(
|
||||
PGF_SYMBOL_KP, PgfSymbolKP,
|
||||
GU_MEMBER(PgfSymbolKP, default_form, PgfTokens),
|
||||
GU_MEMBER(PgfSymbolKP, n_forms, GuLength),
|
||||
GU_FLEX_MEMBER(PgfSymbolKP, forms, PgfAlternative)));
|
||||
|
||||
GU_DEFINE_TYPE(
|
||||
PgfCncCat, struct,
|
||||
GU_MEMBER(PgfCncCat, cid, PgfCId),
|
||||
GU_MEMBER_P(PgfCncCat, cats, PgfCCatIds),
|
||||
GU_MEMBER(PgfCncCat, n_lins, size_t),
|
||||
GU_MEMBER_P(PgfCncCat, lindefs, PgfFunIds),
|
||||
GU_MEMBER_P(PgfCncCat, labels, GuStringL));
|
||||
|
||||
// GU_DEFINE_TYPE(PgfSequence, GuList, gu_ptr_type(PgfSymbol));
|
||||
// GU_DEFINE_TYPE(PgfSequence, GuList, gu_type(PgfSymbol));
|
||||
GU_DEFINE_TYPE(PgfSequence, GuSeq, gu_type(PgfSymbol));
|
||||
|
||||
GU_DEFINE_TYPE(PgfFlags, GuStringMap, gu_type(PgfLiteral), &gu_null_variant);
|
||||
|
||||
typedef PgfFlags* PgfFlagsP;
|
||||
|
||||
GU_DEFINE_TYPE(PgfFlagsP, pointer, gu_type(PgfFlags));
|
||||
|
||||
GU_DEFINE_TYPE(PgfSequences, GuList, gu_type(PgfSequence));
|
||||
|
||||
GU_DEFINE_TYPE(PgfSeqId, typedef, gu_type(PgfSequence));
|
||||
|
||||
GU_DEFINE_TYPE(
|
||||
PgfCncFun, struct,
|
||||
GU_MEMBER(PgfCncFun, fun, PgfCId),
|
||||
GU_MEMBER(PgfCncFun, n_lins, GuLength),
|
||||
GU_FLEX_MEMBER(PgfCncFun, lins, PgfSeqId));
|
||||
|
||||
GU_DEFINE_TYPE(PgfCncFuns, GuList,
|
||||
GU_TYPE_LIT(referenced, _, gu_ptr_type(PgfCncFun)));
|
||||
|
||||
GU_DEFINE_TYPE(PgfFunId, shared, gu_type(PgfCncFun));
|
||||
|
||||
GU_DEFINE_TYPE(PgfFunIds, GuList, gu_type(PgfFunId));
|
||||
|
||||
GU_DEFINE_TYPE(
|
||||
PgfPArg, struct,
|
||||
GU_MEMBER_P(PgfPArg, hypos, PgfCCatIds),
|
||||
GU_MEMBER(PgfPArg, ccat, PgfCCatId));
|
||||
|
||||
GU_DEFINE_TYPE(PgfPArgs, GuSeq, gu_type(PgfPArg));
|
||||
|
||||
GU_DEFINE_TYPE(
|
||||
PgfProduction, GuVariant,
|
||||
GU_CONSTRUCTOR_S(
|
||||
PGF_PRODUCTION_APPLY, PgfProductionApply,
|
||||
GU_MEMBER(PgfProductionApply, fun, PgfFunId),
|
||||
GU_MEMBER(PgfProductionApply, args, PgfPArgs)),
|
||||
GU_CONSTRUCTOR_S(
|
||||
PGF_PRODUCTION_COERCE, PgfProductionCoerce,
|
||||
GU_MEMBER(PgfProductionCoerce, coerce, PgfCCatId)),
|
||||
GU_CONSTRUCTOR_S(
|
||||
PGF_PRODUCTION_CONST, PgfProductionConst,
|
||||
GU_MEMBER(PgfProductionConst, expr, PgfExpr),
|
||||
GU_MEMBER(PgfProductionConst, n_toks, GuLength),
|
||||
GU_FLEX_MEMBER(PgfProductionConst, toks, GuString)));
|
||||
|
||||
GU_DEFINE_TYPE(PgfProductions, GuList, gu_type(PgfProduction));
|
||||
GU_DEFINE_TYPE(PgfProductionSeq, GuSeq, gu_type(PgfProduction));
|
||||
|
||||
GU_DEFINE_TYPE(
|
||||
PgfPatt, GuVariant,
|
||||
GU_CONSTRUCTOR_S(
|
||||
PGF_PATT_APP, PgfPattApp,
|
||||
GU_MEMBER(PgfPattApp, ctor, PgfCId),
|
||||
GU_MEMBER(PgfPattApp, n_args, GuLength),
|
||||
GU_MEMBER(PgfPattApp, args, PgfPatt)),
|
||||
GU_CONSTRUCTOR_S(
|
||||
PGF_PATT_LIT, PgfPattLit,
|
||||
GU_MEMBER(PgfPattLit, lit, PgfLiteral)),
|
||||
GU_CONSTRUCTOR_S(
|
||||
PGF_PATT_VAR, PgfPattVar,
|
||||
GU_MEMBER(PgfPattVar, var, PgfCId)),
|
||||
GU_CONSTRUCTOR_S(
|
||||
PGF_PATT_AS, PgfPattAs,
|
||||
GU_MEMBER(PgfPattAs, var, PgfCId),
|
||||
GU_MEMBER(PgfPattAs, patt, PgfPatt)),
|
||||
GU_CONSTRUCTOR(
|
||||
PGF_PATT_WILD, void),
|
||||
GU_CONSTRUCTOR_S(
|
||||
PGF_PATT_IMPL_ARG, PgfPattImplArg,
|
||||
GU_MEMBER(PgfPattImplArg, patt, PgfPatt)),
|
||||
GU_CONSTRUCTOR_S(
|
||||
PGF_PATT_TILDE, PgfPattTilde,
|
||||
GU_MEMBER(PgfPattTilde, expr, PgfExpr)));
|
||||
|
||||
GU_DEFINE_TYPE(
|
||||
PgfEquation, struct,
|
||||
GU_MEMBER(PgfEquation, body, PgfExpr),
|
||||
GU_MEMBER(PgfEquation, n_patts, GuLength),
|
||||
GU_MEMBER(PgfEquation, patts, PgfPatt));
|
||||
|
||||
// Distinct type so we can give it special treatment in the reader
|
||||
GU_DEFINE_TYPE(PgfEquationsM, GuSeq, gu_type(PgfEquation));
|
||||
|
||||
GU_DEFINE_TYPE(
|
||||
PgfFunDecl, struct,
|
||||
GU_MEMBER_P(PgfFunDecl, type, PgfType),
|
||||
GU_MEMBER(PgfFunDecl, arity, int),
|
||||
GU_MEMBER(PgfFunDecl, defns, PgfEquationsM),
|
||||
GU_MEMBER(PgfFunDecl, prob, double));
|
||||
|
||||
GU_DEFINE_TYPE(
|
||||
PgfCatFun, struct,
|
||||
GU_MEMBER(PgfCatFun, prob, double),
|
||||
GU_MEMBER(PgfCatFun, fun, PgfCId));
|
||||
|
||||
GU_DEFINE_TYPE(
|
||||
PgfCat, struct,
|
||||
GU_MEMBER(PgfCat, context, PgfHypos),
|
||||
GU_MEMBER(PgfCat, n_functions, GuLength),
|
||||
GU_FLEX_MEMBER(PgfCat, functions, PgfCatFun));
|
||||
|
||||
|
||||
GU_DEFINE_TYPE(
|
||||
PgfAbstr, struct,
|
||||
GU_MEMBER(PgfAbstr, aflags, PgfFlagsP),
|
||||
GU_MEMBER_V(PgfAbstr, funs,
|
||||
GU_TYPE_LIT(pointer, PgfCIdMap*,
|
||||
GU_TYPE_LIT(PgfCIdMap, _,
|
||||
gu_ptr_type(PgfFunDecl),
|
||||
&gu_null_struct))),
|
||||
GU_MEMBER_V(PgfAbstr, cats,
|
||||
GU_TYPE_LIT(pointer, PgfCIdMap*,
|
||||
GU_TYPE_LIT(PgfCIdMap, _,
|
||||
gu_ptr_type(PgfCat),
|
||||
&gu_null_struct))));
|
||||
|
||||
GU_DEFINE_TYPE(
|
||||
PgfPrintNames, PgfCIdMap, gu_type(GuString), NULL);
|
||||
|
||||
GU_DEFINE_TYPE(
|
||||
PgfConcr, struct,
|
||||
GU_MEMBER(PgfConcr, cflags, PgfFlagsP),
|
||||
GU_MEMBER_P(PgfConcr, printnames, PgfPrintNames),
|
||||
GU_MEMBER_V(PgfConcr, cnccats,
|
||||
GU_TYPE_LIT(pointer, PgfCIdMap*,
|
||||
GU_TYPE_LIT(PgfCIdMap, _,
|
||||
gu_ptr_type(PgfCncCat),
|
||||
&gu_null_struct))));
|
||||
|
||||
GU_DEFINE_TYPE(
|
||||
PgfPGF, struct,
|
||||
GU_MEMBER(PgfPGF, major_version, uint16_t),
|
||||
GU_MEMBER(PgfPGF, minor_version, uint16_t),
|
||||
GU_MEMBER(PgfPGF, gflags, PgfFlagsP),
|
||||
GU_MEMBER(PgfPGF, absname, PgfCId),
|
||||
GU_MEMBER(PgfPGF, abstract, PgfAbstr),
|
||||
GU_MEMBER_V(PgfPGF, concretes,
|
||||
GU_TYPE_LIT(pointer, PgfCIdMap*,
|
||||
GU_TYPE_LIT(PgfCIdMap, _,
|
||||
gu_ptr_type(PgfConcr),
|
||||
&gu_null_struct))));
|
||||
|
||||
@@ -1,76 +1,330 @@
|
||||
#ifndef PGF_DATA_H
|
||||
#define PGF_DATA_H
|
||||
/*
|
||||
* Copyright 2010 University of Helsinki.
|
||||
*
|
||||
* This file is part of libpgf.
|
||||
*
|
||||
* Libpgf is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Libpgf 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 Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with libpgf. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
typedef int BindType;
|
||||
#ifndef PGF_DATA_H_
|
||||
#define PGF_DATA_H_
|
||||
|
||||
#include "expr.h"
|
||||
#include "type.h"
|
||||
#include <gu/list.h>
|
||||
#include <gu/variant.h>
|
||||
#include <gu/map.h>
|
||||
#include <gu/string.h>
|
||||
#include <gu/type.h>
|
||||
#include <gu/seq.h>
|
||||
#include <pgf/pgf.h>
|
||||
#include <pgf/expr.h>
|
||||
|
||||
struct _String {
|
||||
int len;
|
||||
unsigned int chars[];
|
||||
typedef struct PgfCCat PgfCCat;
|
||||
typedef PgfCCat* PgfCCatId;
|
||||
extern GU_DECLARE_TYPE(PgfCCat, struct);
|
||||
extern GU_DECLARE_TYPE(PgfCCatId, shared);
|
||||
typedef GuList(PgfCCatId) PgfCCatIds;
|
||||
extern GU_DECLARE_TYPE(PgfCCatIds, GuList);
|
||||
typedef GuSeq PgfCCatSeq;
|
||||
extern GU_DECLARE_TYPE(PgfCCatSeq, GuSeq);
|
||||
|
||||
typedef struct PgfAbstr PgfAbstr;
|
||||
typedef struct PgfFunDecl PgfFunDecl;
|
||||
typedef struct PgfConcr PgfConcr;
|
||||
|
||||
typedef int PgfLength;
|
||||
typedef struct GuVariant PgfSymbol;
|
||||
typedef struct PgfAlternative PgfAlternative;
|
||||
typedef struct PgfCncFun PgfCncFun;
|
||||
|
||||
|
||||
typedef GuSeq PgfSequence; // -> PgfSymbol
|
||||
|
||||
typedef PgfCncFun* PgfFunId; // key to PgfCncFuns
|
||||
extern GU_DECLARE_TYPE(PgfFunId, shared);
|
||||
typedef GuList(PgfCncFun*) PgfCncFuns;
|
||||
extern GU_DECLARE_TYPE(PgfCncFuns, GuList);
|
||||
typedef GuList(PgfFunId) PgfFunIds;
|
||||
extern GU_DECLARE_TYPE(PgfFunIds, GuList);
|
||||
// typedef GuStringMap PgfCIdMap; // PgfCId -> ?
|
||||
#define PgfCIdMap GuStringMap
|
||||
typedef PgfCIdMap PgfFlags; // PgfCId -> PgfLiteral
|
||||
extern GU_DECLARE_TYPE(PgfFlags, GuMap);
|
||||
|
||||
extern GU_DECLARE_TYPE(PgfType, struct);
|
||||
typedef GuVariant PgfProduction;
|
||||
typedef GuList(PgfProduction) PgfProductions;
|
||||
extern GU_DECLARE_TYPE(PgfProductions, GuList);
|
||||
typedef GuSeq PgfProductionSeq;
|
||||
extern GU_DECLARE_TYPE(PgfProductionSeq, GuSeq);
|
||||
|
||||
typedef struct PgfCatFun PgfCatFun;
|
||||
typedef struct PgfCncCat PgfCncCat;
|
||||
extern GU_DECLARE_TYPE(PgfCncCat, struct);
|
||||
typedef GuVariant PgfPatt;
|
||||
|
||||
typedef GuList(GuString) GuStringL;
|
||||
extern GU_DECLARE_TYPE(GuStringL, GuList);
|
||||
typedef GuSeq PgfTokens; // -> PgfToken
|
||||
extern GU_DECLARE_TYPE(PgfTokens, GuSeq);
|
||||
|
||||
bool
|
||||
pgf_tokens_equal(PgfTokens t1, PgfTokens t2);
|
||||
|
||||
|
||||
|
||||
typedef PgfExpr PgfTree;
|
||||
|
||||
typedef struct PgfEquation PgfEquation;
|
||||
typedef GuSeq PgfEquations;
|
||||
typedef PgfEquations PgfEquationsM; // can be null
|
||||
extern GU_DECLARE_TYPE(PgfEquationsM, GuSeq);
|
||||
typedef struct PgfCat PgfCat;
|
||||
|
||||
typedef PgfSequence PgfSeqId; // shared reference
|
||||
|
||||
extern GU_DECLARE_TYPE(PgfSeqId, typedef);
|
||||
|
||||
typedef GuList(PgfSequence) PgfSequences;
|
||||
|
||||
extern GU_DECLARE_TYPE(PgfSequences, GuList);
|
||||
|
||||
|
||||
|
||||
|
||||
struct PgfAbstr {
|
||||
PgfFlags* aflags;
|
||||
PgfCIdMap* funs; // |-> PgfFunDecl*
|
||||
PgfCIdMap* cats; // |-> PgfCat*
|
||||
};
|
||||
|
||||
struct _CId {
|
||||
int len;
|
||||
char chars[];
|
||||
struct PgfPGF {
|
||||
uint16_t major_version;
|
||||
uint16_t minor_version;
|
||||
PgfFlags* gflags;
|
||||
PgfCId absname;
|
||||
PgfAbstr abstract;
|
||||
PgfCIdMap* concretes; // |-> PgfConcr*
|
||||
GuPool* pool;
|
||||
};
|
||||
|
||||
typedef struct _CIdList {
|
||||
int count;
|
||||
CId names[];
|
||||
} *CIdList;
|
||||
extern GU_DECLARE_TYPE(PgfPGF, struct);
|
||||
|
||||
typedef struct _AbsCat {
|
||||
CId name;
|
||||
Context hypos;
|
||||
CIdList funs;
|
||||
} *AbsCat;
|
||||
|
||||
typedef struct _AbsCats {
|
||||
int count;
|
||||
struct _AbsCat lst[];
|
||||
} *AbsCats;
|
||||
|
||||
typedef struct _AbsFun {
|
||||
CId name;
|
||||
Type ty;
|
||||
int arrity;
|
||||
Equations equs;
|
||||
} *AbsFun;
|
||||
|
||||
typedef struct _AbsFuns {
|
||||
int count;
|
||||
struct _AbsFun lst[];
|
||||
} *AbsFuns;
|
||||
|
||||
struct _Flag {
|
||||
CId name;
|
||||
Literal value;
|
||||
} ;
|
||||
|
||||
typedef struct _Flags {
|
||||
int count;
|
||||
struct _Flag values[];
|
||||
} *Flags;
|
||||
|
||||
typedef struct _Abstract {
|
||||
CId name;
|
||||
Flags flags;
|
||||
AbsFuns funs;
|
||||
AbsCats cats;
|
||||
} *Abstract;
|
||||
|
||||
typedef struct _Concrete {
|
||||
CId name;
|
||||
Flags flags;
|
||||
} *Concrete;
|
||||
|
||||
struct _PGF {
|
||||
Flags flags;
|
||||
int nConcr;
|
||||
struct _Abstract abstract;
|
||||
struct _Concrete concretes[];
|
||||
struct PgfFunDecl {
|
||||
PgfType* type;
|
||||
int arity; // Only for computational defs?
|
||||
PgfEquationsM defns; // maybe null
|
||||
double prob;
|
||||
};
|
||||
|
||||
#endif
|
||||
struct PgfCatFun {
|
||||
double prob;
|
||||
PgfCId fun;
|
||||
};
|
||||
|
||||
struct PgfCat {
|
||||
// TODO: Add cid here
|
||||
PgfHypos context;
|
||||
GuLength n_functions;
|
||||
PgfCatFun functions[]; // XXX: resolve to PgfFunDecl*?
|
||||
};
|
||||
|
||||
|
||||
struct PgfCncCat {
|
||||
PgfCId cid;
|
||||
PgfCCatIds* cats;
|
||||
PgfFunIds* lindefs;
|
||||
size_t n_lins;
|
||||
|
||||
GuStringL* labels;
|
||||
/**< Labels for tuples. All nested tuples, records and tables
|
||||
* in the GF linearization types are flattened into a single
|
||||
* tuple in the corresponding PGF concrete category. This
|
||||
* field holds the labels that indicate which GF field or
|
||||
* parameter (or their combination) each tuple element
|
||||
* represents. */
|
||||
};
|
||||
|
||||
struct PgfCncFun {
|
||||
PgfCId fun; // XXX: resolve to PgfFunDecl*?
|
||||
GuLength n_lins;
|
||||
PgfSeqId lins[];
|
||||
};
|
||||
|
||||
struct PgfAlternative {
|
||||
PgfTokens form;
|
||||
/**< The form of this variant as a list of tokens. */
|
||||
|
||||
GuStringL* prefixes;
|
||||
/**< The prefixes of the following symbol that trigger this
|
||||
* form. */
|
||||
};
|
||||
|
||||
struct PgfCCat {
|
||||
PgfCncCat* cnccat;
|
||||
PgfProductionSeq prods;
|
||||
int fid;
|
||||
};
|
||||
|
||||
extern PgfCCat pgf_ccat_string, pgf_ccat_int, pgf_ccat_float, pgf_ccat_var;
|
||||
|
||||
typedef PgfCIdMap PgfPrintNames;
|
||||
extern GU_DECLARE_TYPE(PgfPrintNames, GuStringMap);
|
||||
|
||||
struct PgfConcr {
|
||||
PgfFlags* cflags;
|
||||
PgfPrintNames* printnames;
|
||||
PgfCIdMap* cnccats;
|
||||
PgfCCatSeq extra_ccats;
|
||||
};
|
||||
|
||||
extern GU_DECLARE_TYPE(PgfConcr, struct);
|
||||
|
||||
typedef enum {
|
||||
PGF_SYMBOL_CAT,
|
||||
PGF_SYMBOL_LIT,
|
||||
PGF_SYMBOL_VAR,
|
||||
PGF_SYMBOL_KS,
|
||||
PGF_SYMBOL_KP
|
||||
} PgfSymbolTag;
|
||||
|
||||
typedef struct PgfSymbolIdx PgfSymbolIdx;
|
||||
|
||||
struct PgfSymbolIdx {
|
||||
int d;
|
||||
int r;
|
||||
};
|
||||
|
||||
typedef PgfSymbolIdx PgfSymbolCat, PgfSymbolLit, PgfSymbolVar;
|
||||
|
||||
typedef struct {
|
||||
PgfTokens tokens;
|
||||
} PgfSymbolKS;
|
||||
|
||||
typedef struct PgfSymbolKP
|
||||
/** A prefix-dependent symbol. The form that this symbol takes
|
||||
* depends on the form of a prefix of the following symbol. */
|
||||
{
|
||||
PgfTokens default_form;
|
||||
/**< Default form that this symbol takes if none of of the
|
||||
* variant forms is triggered. */
|
||||
|
||||
GuLength n_forms;
|
||||
PgfAlternative forms[];
|
||||
/**< Variant forms whose choise depends on the following
|
||||
* symbol. */
|
||||
} PgfSymbolKP;
|
||||
|
||||
|
||||
|
||||
|
||||
// PgfProduction
|
||||
|
||||
typedef enum {
|
||||
PGF_PRODUCTION_APPLY,
|
||||
PGF_PRODUCTION_COERCE,
|
||||
PGF_PRODUCTION_CONST
|
||||
} PgfProductionTag;
|
||||
|
||||
typedef struct PgfPArg PgfPArg;
|
||||
|
||||
struct PgfPArg {
|
||||
PgfCCatId ccat;
|
||||
PgfCCatIds* hypos;
|
||||
};
|
||||
|
||||
GU_DECLARE_TYPE(PgfPArg, struct);
|
||||
|
||||
typedef GuSeq PgfPArgs;
|
||||
|
||||
GU_DECLARE_TYPE(PgfPArgs, GuSeq);
|
||||
|
||||
typedef struct {
|
||||
PgfFunId fun;
|
||||
PgfPArgs args;
|
||||
} PgfProductionApply;
|
||||
|
||||
typedef struct PgfProductionCoerce
|
||||
/** A coercion. This production is a logical union of the coercions of
|
||||
* another FId. This allows common subsets of productions to be
|
||||
* shared. */
|
||||
{
|
||||
PgfCCatId coerce;
|
||||
} PgfProductionCoerce;
|
||||
|
||||
typedef struct {
|
||||
PgfExpr expr; // XXX
|
||||
GuLength n_toks;
|
||||
GuString toks[]; // XXX
|
||||
} PgfProductionConst;
|
||||
|
||||
|
||||
extern GU_DECLARE_TYPE(PgfProduction, GuVariant);
|
||||
extern GU_DECLARE_TYPE(PgfBindType, enum);
|
||||
extern GU_DECLARE_TYPE(PgfLiteral, GuVariant);
|
||||
|
||||
|
||||
PgfCCatId
|
||||
pgf_literal_cat(PgfLiteral lit);
|
||||
|
||||
// PgfPatt
|
||||
|
||||
typedef enum {
|
||||
PGF_PATT_APP,
|
||||
PGF_PATT_LIT,
|
||||
PGF_PATT_VAR,
|
||||
PGF_PATT_AS,
|
||||
PGF_PATT_WILD,
|
||||
PGF_PATT_IMPL_ARG,
|
||||
PGF_PATT_TILDE,
|
||||
PGF_PATT_NUM_TAGS
|
||||
} PgfPattTag;
|
||||
|
||||
typedef struct {
|
||||
PgfCId ctor;
|
||||
GuLength n_args;
|
||||
PgfPatt args[];
|
||||
} PgfPattApp;
|
||||
|
||||
typedef struct {
|
||||
PgfLiteral* lit;
|
||||
} PgfPattLit;
|
||||
|
||||
typedef struct {
|
||||
PgfCId var;
|
||||
} PgfPattVar;
|
||||
|
||||
typedef struct {
|
||||
PgfCId var;
|
||||
PgfPatt patt;
|
||||
} PgfPattAs;
|
||||
|
||||
typedef void PgfPattWild;
|
||||
|
||||
typedef struct {
|
||||
PgfPatt patt;
|
||||
} PgfPattImplArg;
|
||||
|
||||
typedef struct {
|
||||
PgfExpr expr;
|
||||
} PgfPattTilde;
|
||||
|
||||
struct PgfEquation {
|
||||
PgfExpr body;
|
||||
GuLength n_patts;
|
||||
PgfPatt patts[];
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif /* PGF_PRIVATE_H_ */
|
||||
|
||||
20
src/runtime/c/pgf/edsl.h
Normal file
20
src/runtime/c/pgf/edsl.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef PGF_EDSL_H_
|
||||
#define PGF_EDSL_H_
|
||||
|
||||
#include <pgf/expr.h>
|
||||
|
||||
#define APP(f, a) \
|
||||
gu_new_variant_i(PGF_EDSL_POOL, PGF_EXPR_APP, PgfExprApp, f, a)
|
||||
#define APP2(f, a1, a2) APP(APP(f, a1), a2)
|
||||
#define APP3(f, a1, a2, a3) APP2(APP(f, a1), a2, a3)
|
||||
|
||||
#define VAR(s) \
|
||||
gu_new_variant_i(PGF_EDSL_POOL, PGF_EXPR_FUN, PgfExprFun, gu_cstring(#s))
|
||||
|
||||
#define APPV(s, a) APP(VAR(s), a)
|
||||
#define APPV2(s, a1, a2) APP2(VAR(s), a1, a2)
|
||||
#define APPV3(s, a1, a2, a3) APP3(VAR(s), a1, a2)
|
||||
|
||||
|
||||
|
||||
#endif // PGF_EDSL_H_
|
||||
334
src/runtime/c/pgf/expr.c
Normal file
334
src/runtime/c/pgf/expr.c
Normal file
@@ -0,0 +1,334 @@
|
||||
#include "expr.h"
|
||||
#include <gu/intern.h>
|
||||
#include <gu/assert.h>
|
||||
#include <ctype.h>
|
||||
|
||||
|
||||
PgfExpr
|
||||
pgf_expr_unwrap(PgfExpr expr)
|
||||
{
|
||||
while (true) {
|
||||
GuVariantInfo i = gu_variant_open(expr);
|
||||
switch (i.tag) {
|
||||
case PGF_EXPR_IMPL_ARG: {
|
||||
PgfExprImplArg* eimpl = i.data;
|
||||
expr = eimpl->expr;
|
||||
break;
|
||||
}
|
||||
case PGF_EXPR_TYPED: {
|
||||
PgfExprTyped* etyped = i.data;
|
||||
expr = etyped->expr;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return expr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
pgf_expr_arity(PgfExpr expr)
|
||||
{
|
||||
int n = 0;
|
||||
while (true) {
|
||||
PgfExpr e = pgf_expr_unwrap(expr);
|
||||
GuVariantInfo i = gu_variant_open(e);
|
||||
switch (i.tag) {
|
||||
case PGF_EXPR_APP: {
|
||||
PgfExprApp* app = i.data;
|
||||
expr = app->fun;
|
||||
n = n + 1;
|
||||
break;
|
||||
}
|
||||
case PGF_EXPR_FUN:
|
||||
return n;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PgfApplication*
|
||||
pgf_expr_unapply(PgfExpr expr, GuPool* pool)
|
||||
{
|
||||
int arity = pgf_expr_arity(expr);
|
||||
if (arity < 0) {
|
||||
return NULL;
|
||||
}
|
||||
PgfApplication* appl = gu_new_flex(pool, PgfApplication, args, arity);
|
||||
appl->n_args = arity;
|
||||
for (int n = arity - 1; n >= 0; n--) {
|
||||
PgfExpr e = pgf_expr_unwrap(expr);
|
||||
gu_assert(gu_variant_tag(e) == PGF_EXPR_APP);
|
||||
PgfExprApp* app = gu_variant_data(e);
|
||||
appl->args[n] = app->arg;
|
||||
expr = app->fun;
|
||||
}
|
||||
PgfExpr e = pgf_expr_unwrap(expr);
|
||||
gu_assert(gu_variant_tag(e) == PGF_EXPR_FUN);
|
||||
PgfExprFun* fun = gu_variant_data(e);
|
||||
appl->fun = fun->fun;
|
||||
return appl;
|
||||
}
|
||||
|
||||
GU_DEFINE_TYPE(PgfBindType, enum,
|
||||
GU_ENUM_C(PgfBindType, PGF_BIND_TYPE_EXPLICIT),
|
||||
GU_ENUM_C(PgfBindType, PGF_BIND_TYPE_IMPLICIT));
|
||||
|
||||
GU_DEFINE_TYPE(PgfLiteral, GuVariant,
|
||||
GU_CONSTRUCTOR_S(PGF_LITERAL_STR, PgfLiteralStr,
|
||||
GU_MEMBER(PgfLiteralStr, val, GuString)),
|
||||
GU_CONSTRUCTOR_S(PGF_LITERAL_INT, PgfLiteralInt,
|
||||
GU_MEMBER(PgfLiteralInt, val, int)),
|
||||
GU_CONSTRUCTOR_S(PGF_LITERAL_FLT, PgfLiteralFlt,
|
||||
GU_MEMBER(PgfLiteralFlt, val, double)));
|
||||
|
||||
GU_DECLARE_TYPE(PgfType, struct);
|
||||
|
||||
GU_DEFINE_TYPE(PgfHypo, struct,
|
||||
GU_MEMBER(PgfHypo, bindtype, PgfBindType),
|
||||
GU_MEMBER(PgfHypo, cid, PgfCId),
|
||||
GU_MEMBER_P(PgfHypo, type, PgfType));
|
||||
|
||||
GU_DEFINE_TYPE(PgfHypos, GuSeq, gu_type(PgfHypo));
|
||||
|
||||
GU_DEFINE_TYPE(PgfType, struct,
|
||||
GU_MEMBER(PgfType, hypos, PgfHypos),
|
||||
GU_MEMBER(PgfType, cid, PgfCId),
|
||||
GU_MEMBER(PgfType, n_exprs, GuLength),
|
||||
GU_FLEX_MEMBER(PgfType, exprs, PgfExpr));
|
||||
|
||||
GU_DEFINE_TYPE(
|
||||
PgfExpr, GuVariant,
|
||||
GU_CONSTRUCTOR_S(
|
||||
PGF_EXPR_ABS, PgfExprAbs,
|
||||
GU_MEMBER(PgfExprAbs, bind_type, PgfBindType),
|
||||
GU_MEMBER(PgfExprAbs, id, GuStr),
|
||||
GU_MEMBER(PgfExprAbs, body, PgfExpr)),
|
||||
GU_CONSTRUCTOR_S(
|
||||
PGF_EXPR_APP, PgfExprApp,
|
||||
GU_MEMBER(PgfExprApp, fun, PgfExpr),
|
||||
GU_MEMBER(PgfExprApp, arg, PgfExpr)),
|
||||
GU_CONSTRUCTOR_S(
|
||||
PGF_EXPR_LIT, PgfExprLit,
|
||||
GU_MEMBER(PgfExprLit, lit, PgfLiteral)),
|
||||
GU_CONSTRUCTOR_S(
|
||||
PGF_EXPR_META, PgfExprMeta,
|
||||
GU_MEMBER(PgfExprMeta, id, int)),
|
||||
GU_CONSTRUCTOR_S(
|
||||
PGF_EXPR_FUN, PgfExprFun,
|
||||
GU_MEMBER(PgfExprFun, fun, GuStr)),
|
||||
GU_CONSTRUCTOR_S(
|
||||
PGF_EXPR_VAR, PgfExprVar,
|
||||
GU_MEMBER(PgfExprVar, var, int)),
|
||||
GU_CONSTRUCTOR_S(
|
||||
PGF_EXPR_TYPED, PgfExprTyped,
|
||||
GU_MEMBER(PgfExprTyped, expr, PgfExpr),
|
||||
GU_MEMBER_P(PgfExprTyped, type, PgfType)),
|
||||
GU_CONSTRUCTOR_S(
|
||||
PGF_EXPR_IMPL_ARG, PgfExprImplArg,
|
||||
GU_MEMBER(PgfExprImplArg, expr, PgfExpr)));
|
||||
|
||||
|
||||
typedef struct PgfExprParser PgfExprParser;
|
||||
|
||||
struct PgfExprParser {
|
||||
GuReader* rdr;
|
||||
GuIntern* intern;
|
||||
GuExn* err;
|
||||
GuPool* expr_pool;
|
||||
const char* lookahead;
|
||||
int next_char;
|
||||
};
|
||||
|
||||
|
||||
static const char pgf_expr_lpar[] = "(";
|
||||
static const char pgf_expr_rpar[] = ")";
|
||||
static const char pgf_expr_semic[] = ";";
|
||||
|
||||
static char
|
||||
pgf_expr_parser_next(PgfExprParser* parser)
|
||||
{
|
||||
if (parser->next_char >= 0) {
|
||||
char ret = (char) parser->next_char;
|
||||
parser->next_char = -1;
|
||||
return ret;
|
||||
}
|
||||
return gu_getc(parser->rdr, parser->err);
|
||||
}
|
||||
|
||||
static const char*
|
||||
pgf_expr_parser_lookahead(PgfExprParser* parser)
|
||||
{
|
||||
if (parser->lookahead != NULL) {
|
||||
return parser->lookahead;
|
||||
}
|
||||
const char* str = NULL;
|
||||
char c;
|
||||
do {
|
||||
c = pgf_expr_parser_next(parser);
|
||||
if (!gu_ok(parser->err)) {
|
||||
return NULL;
|
||||
}
|
||||
} while (isspace(c));
|
||||
switch (c) {
|
||||
case '(':
|
||||
str = pgf_expr_lpar;
|
||||
break;
|
||||
case ')':
|
||||
str = pgf_expr_rpar;
|
||||
break;
|
||||
case ';':
|
||||
str = pgf_expr_semic;
|
||||
break;
|
||||
default:
|
||||
if (isalpha(c)) {
|
||||
GuPool* tmp_pool = gu_new_pool();
|
||||
GuCharBuf* chars = gu_new_buf(char, tmp_pool);
|
||||
while (isalnum(c) || c == '_') {
|
||||
gu_buf_push(chars, char, c);
|
||||
c = pgf_expr_parser_next(parser);
|
||||
if (!gu_ok(parser->err)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
parser->next_char = (unsigned char) c;
|
||||
char* tmp_str = gu_chars_str(gu_buf_seq(chars),
|
||||
tmp_pool);
|
||||
str = gu_intern_str(parser->intern, tmp_str);
|
||||
gu_pool_free(tmp_pool);
|
||||
}
|
||||
}
|
||||
parser->lookahead = str;
|
||||
return str;
|
||||
}
|
||||
|
||||
static bool
|
||||
pgf_expr_parser_token_is_id(const char* str)
|
||||
{
|
||||
if (str == NULL || !str[0]) {
|
||||
return false;
|
||||
}
|
||||
char c = str[0];
|
||||
return (isalpha(c) || c == '_');
|
||||
}
|
||||
|
||||
static void
|
||||
pgf_expr_parser_consume(PgfExprParser* parser)
|
||||
{
|
||||
pgf_expr_parser_lookahead(parser);
|
||||
parser->lookahead = NULL;
|
||||
}
|
||||
|
||||
static PgfExpr
|
||||
pgf_expr_parser_expr(PgfExprParser* parser);
|
||||
|
||||
static PgfExpr
|
||||
pgf_expr_parser_term(PgfExprParser* parser)
|
||||
{
|
||||
const char* la = pgf_expr_parser_lookahead(parser);
|
||||
|
||||
if (la == pgf_expr_lpar) {
|
||||
pgf_expr_parser_consume(parser);
|
||||
PgfExpr expr = pgf_expr_parser_expr(parser);
|
||||
la = pgf_expr_parser_lookahead(parser);
|
||||
if (la == pgf_expr_rpar) {
|
||||
pgf_expr_parser_consume(parser);
|
||||
return expr;
|
||||
}
|
||||
} else if (pgf_expr_parser_token_is_id(la)) {
|
||||
pgf_expr_parser_consume(parser);
|
||||
GuString s = gu_str_string(la, parser->expr_pool);
|
||||
return gu_new_variant_i(parser->expr_pool,
|
||||
PGF_EXPR_FUN,
|
||||
PgfExprFun,
|
||||
s);
|
||||
}
|
||||
return gu_null_variant;
|
||||
}
|
||||
|
||||
static PgfExpr
|
||||
pgf_expr_parser_expr(PgfExprParser* parser)
|
||||
{
|
||||
PgfExpr expr = pgf_expr_parser_term(parser);
|
||||
if (gu_variant_is_null(expr))
|
||||
{
|
||||
return expr;
|
||||
}
|
||||
while (true) {
|
||||
PgfExpr arg = pgf_expr_parser_term(parser);
|
||||
if (gu_variant_is_null(arg)) {
|
||||
return expr;
|
||||
}
|
||||
expr = gu_new_variant_i(parser->expr_pool,
|
||||
PGF_EXPR_APP,
|
||||
PgfExprApp,
|
||||
expr, arg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
PgfExpr
|
||||
pgf_read_expr(GuReader* rdr, GuPool* pool, GuExn* err)
|
||||
{
|
||||
GuPool* tmp_pool = gu_new_pool();
|
||||
PgfExprParser* parser = gu_new(PgfExprParser, tmp_pool);
|
||||
parser->rdr = rdr;
|
||||
parser->intern = gu_new_intern(pool, tmp_pool);
|
||||
parser->expr_pool = pool;
|
||||
parser->err = err;
|
||||
parser->lookahead = NULL;
|
||||
parser->next_char = -1;
|
||||
PgfExpr expr = pgf_expr_parser_expr(parser);
|
||||
const char* la = pgf_expr_parser_lookahead(parser);
|
||||
if (la == pgf_expr_semic) {
|
||||
pgf_expr_parser_consume(parser);
|
||||
} else {
|
||||
expr = gu_null_variant;
|
||||
}
|
||||
gu_pool_free(tmp_pool);
|
||||
return expr;
|
||||
}
|
||||
|
||||
static void
|
||||
pgf_expr_print_with_paren(PgfExpr expr, bool need_paren,
|
||||
GuWriter* wtr, GuExn* err)
|
||||
{
|
||||
GuVariantInfo ei = gu_variant_open(expr);
|
||||
switch (ei.tag) {
|
||||
case PGF_EXPR_FUN: {
|
||||
PgfExprFun* fun = ei.data;
|
||||
gu_string_write(fun->fun, wtr, err);
|
||||
break;
|
||||
}
|
||||
case PGF_EXPR_APP: {
|
||||
PgfExprApp* app = ei.data;
|
||||
if (need_paren) {
|
||||
gu_puts("(", wtr, err);
|
||||
}
|
||||
pgf_expr_print_with_paren(app->fun, false, wtr, err);
|
||||
gu_puts(" ", wtr, err);
|
||||
pgf_expr_print_with_paren(app->arg, true, wtr, err);
|
||||
if (need_paren) {
|
||||
gu_puts(")", wtr, err);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PGF_EXPR_ABS:
|
||||
case PGF_EXPR_LIT:
|
||||
case PGF_EXPR_META:
|
||||
case PGF_EXPR_VAR:
|
||||
case PGF_EXPR_TYPED:
|
||||
case PGF_EXPR_IMPL_ARG:
|
||||
gu_impossible();
|
||||
break;
|
||||
default:
|
||||
gu_impossible();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pgf_expr_print(PgfExpr expr, GuWriter* wtr, GuExn* err) {
|
||||
pgf_expr_print_with_paren(expr, false, wtr, err);
|
||||
}
|
||||
@@ -1,144 +1,152 @@
|
||||
#ifndef PGF_EXPR_H
|
||||
#define PGF_EXPR_H
|
||||
#ifndef EXPR_H_
|
||||
#define EXPR_H_
|
||||
|
||||
#define LIT_STR 0
|
||||
#define LIT_INT 1
|
||||
#define LIT_FLOAT 2
|
||||
#include <gu/read.h>
|
||||
#include <gu/write.h>
|
||||
#include <gu/variant.h>
|
||||
#include <gu/seq.h>
|
||||
#include <pgf/pgf.h>
|
||||
|
||||
struct _Literal {
|
||||
int tag;
|
||||
/// Abstract syntax trees
|
||||
/// @file
|
||||
|
||||
/// An abstract syntax tree
|
||||
typedef GuVariant PgfExpr;
|
||||
|
||||
GU_DECLARE_TYPE(PgfExpr, GuVariant);
|
||||
|
||||
typedef GuList(PgfExpr) PgfExprs;
|
||||
|
||||
typedef struct PgfHypo PgfHypo;
|
||||
typedef struct PgfType PgfType;
|
||||
|
||||
typedef int PgfMetaId;
|
||||
|
||||
typedef enum {
|
||||
PGF_BIND_TYPE_EXPLICIT,
|
||||
PGF_BIND_TYPE_IMPLICIT
|
||||
} PgfBindType;
|
||||
|
||||
// PgfLiteral
|
||||
|
||||
typedef GuVariant PgfLiteral;
|
||||
|
||||
|
||||
typedef enum {
|
||||
PGF_LITERAL_STR,
|
||||
PGF_LITERAL_INT,
|
||||
PGF_LITERAL_FLT,
|
||||
PGF_LITERAL_NUM_TAGS
|
||||
} PgfLiteralTag;
|
||||
|
||||
typedef struct {
|
||||
GuStr val;
|
||||
} PgfLiteralStr;
|
||||
|
||||
typedef struct {
|
||||
int val;
|
||||
} PgfLiteralInt;
|
||||
|
||||
typedef struct {
|
||||
double val;
|
||||
} PgfLiteralFlt;
|
||||
|
||||
|
||||
|
||||
struct PgfHypo {
|
||||
PgfBindType bindtype;
|
||||
|
||||
PgfCId cid;
|
||||
/**< Locally scoped name for the parameter if dependent types
|
||||
* are used. "_" for normal parameters. */
|
||||
|
||||
PgfType* type;
|
||||
};
|
||||
|
||||
typedef struct _LiteralStr {
|
||||
struct _Literal _;
|
||||
String val;
|
||||
} *LiteralStr;
|
||||
typedef GuSeq PgfHypos;
|
||||
extern GU_DECLARE_TYPE(PgfHypos, GuSeq);
|
||||
|
||||
typedef struct _LiteralInt {
|
||||
struct _Literal _;
|
||||
int val;
|
||||
} *LiteralInt;
|
||||
|
||||
typedef struct _LiteralFloat {
|
||||
struct _Literal _;
|
||||
double val;
|
||||
} *LiteralFloat;
|
||||
|
||||
#define TAG_ABS 0
|
||||
#define TAG_APP 1
|
||||
#define TAG_LIT 2
|
||||
#define TAG_MET 3
|
||||
#define TAG_FUN 4
|
||||
#define TAG_VAR 5
|
||||
#define TAG_TYP 6
|
||||
#define TAG_IMP 7
|
||||
|
||||
struct _Expr {
|
||||
int tag;
|
||||
struct PgfType {
|
||||
PgfHypos hypos;
|
||||
PgfCId cid; /// XXX: resolve to PgfCat*?
|
||||
int n_exprs;
|
||||
PgfExpr exprs[];
|
||||
};
|
||||
|
||||
typedef struct _ExprAbs {
|
||||
struct _Expr _;
|
||||
BindType bt;
|
||||
CId var;
|
||||
Expr body;
|
||||
} *ExprAbs;
|
||||
|
||||
typedef enum {
|
||||
PGF_EXPR_ABS,
|
||||
PGF_EXPR_APP,
|
||||
PGF_EXPR_LIT,
|
||||
PGF_EXPR_META,
|
||||
PGF_EXPR_FUN,
|
||||
PGF_EXPR_VAR,
|
||||
PGF_EXPR_TYPED,
|
||||
PGF_EXPR_IMPL_ARG,
|
||||
PGF_EXPR_NUM_TAGS
|
||||
} PgfExprTag;
|
||||
|
||||
typedef struct _ExprApp {
|
||||
struct _Expr _;
|
||||
Expr left, right;
|
||||
} *ExprApp;
|
||||
typedef struct {
|
||||
PgfBindType bind_type;
|
||||
PgfCId id; //
|
||||
PgfExpr body;
|
||||
} PgfExprAbs;
|
||||
|
||||
typedef struct {
|
||||
PgfExpr fun;
|
||||
PgfExpr arg;
|
||||
} PgfExprApp;
|
||||
|
||||
typedef struct _ExprLit {
|
||||
struct _Expr _;
|
||||
Literal lit;
|
||||
} *ExprLit;
|
||||
typedef struct {
|
||||
PgfLiteral lit;
|
||||
} PgfExprLit;
|
||||
|
||||
typedef struct _ExprMeta {
|
||||
struct _Expr _;
|
||||
int id;
|
||||
} *ExprMeta;
|
||||
typedef struct {
|
||||
PgfMetaId id;
|
||||
} PgfExprMeta;
|
||||
|
||||
typedef struct _ExprFun {
|
||||
struct _Expr _;
|
||||
CId fun;
|
||||
} *ExprFun;
|
||||
typedef struct {
|
||||
PgfCId fun;
|
||||
} PgfExprFun;
|
||||
|
||||
typedef struct _ExprVar {
|
||||
struct _Expr _;
|
||||
int index;
|
||||
} *ExprVar;
|
||||
typedef struct {
|
||||
int var;
|
||||
} PgfExprVar;
|
||||
|
||||
typedef struct _ExprTyped {
|
||||
struct _Expr _;
|
||||
Expr e;
|
||||
Type ty;
|
||||
} *ExprTyped;
|
||||
/**< A variable. The value is a de Bruijn index to the environment,
|
||||
* beginning from the innermost variable. */
|
||||
|
||||
typedef struct _ExprImplArg {
|
||||
struct _Expr _;
|
||||
Expr e;
|
||||
} *ExprImplArg;
|
||||
typedef struct {
|
||||
PgfExpr expr;
|
||||
PgfType* type;
|
||||
} PgfExprTyped;
|
||||
|
||||
#define TAG_PAPP 0
|
||||
#define TAG_PVAR 1
|
||||
#define TAG_PAT 2
|
||||
#define TAG_PWILD 3
|
||||
#define TAG_PLIT 4
|
||||
#define TAG_PIMP 5
|
||||
#define TAG_PTILDE 6
|
||||
typedef struct {
|
||||
PgfExpr expr;
|
||||
} PgfExprImplArg;
|
||||
|
||||
typedef struct _Patt {
|
||||
int tag;
|
||||
} *Patt;
|
||||
int
|
||||
pgf_expr_arity(PgfExpr expr);
|
||||
|
||||
typedef struct _Patts {
|
||||
int count;
|
||||
Patt pats[];
|
||||
} *Patts;
|
||||
PgfExpr
|
||||
pgf_expr_unwrap(PgfExpr expr);
|
||||
|
||||
typedef struct _PattApp {
|
||||
struct _Patt _;
|
||||
CId fun;
|
||||
struct _Patts args;
|
||||
} *PattApp;
|
||||
typedef struct PgfApplication PgfApplication;
|
||||
|
||||
typedef struct _PattVar {
|
||||
struct _Patt _;
|
||||
CId var;
|
||||
} *PattVar;
|
||||
struct PgfApplication {
|
||||
PgfCId fun;
|
||||
int n_args;
|
||||
PgfExpr args[];
|
||||
};
|
||||
|
||||
typedef struct _PattAt {
|
||||
struct _Patt _;
|
||||
CId var;
|
||||
Patt pat;
|
||||
} *PattAt;
|
||||
PgfApplication*
|
||||
pgf_expr_unapply(PgfExpr expr, GuPool* pool);
|
||||
|
||||
typedef struct _PattWild {
|
||||
struct _Patt _;
|
||||
} *PattWild;
|
||||
|
||||
typedef struct _PattLit {
|
||||
struct _Patt _;
|
||||
Literal lit;
|
||||
} *PattLit;
|
||||
PgfExpr
|
||||
pgf_read_expr(GuReader* rdr, GuPool* pool, GuExn* err);
|
||||
|
||||
typedef struct _PattImplArg {
|
||||
struct _Patt _;
|
||||
Patt pat;
|
||||
} *PattImplArg;
|
||||
void
|
||||
pgf_expr_print(PgfExpr expr, GuWriter* wtr, GuExn* err);
|
||||
|
||||
typedef struct _PattTilde {
|
||||
struct _Patt _;
|
||||
Expr e;
|
||||
} *PattTilde;
|
||||
|
||||
typedef struct _Equations {
|
||||
int count;
|
||||
struct _Equation {
|
||||
Patts lhs;
|
||||
Expr rhs;
|
||||
} equs[];
|
||||
} *Equations;
|
||||
|
||||
#endif
|
||||
#endif /* EXPR_H_ */
|
||||
|
||||
613
src/runtime/c/pgf/linearize.c
Normal file
613
src/runtime/c/pgf/linearize.c
Normal file
@@ -0,0 +1,613 @@
|
||||
/*
|
||||
* Copyright 2010 University of Helsinki.
|
||||
*
|
||||
* This file is part of libpgf.
|
||||
*
|
||||
* Libpgf is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Libpgf 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 Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with libpgf. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "data.h"
|
||||
#include "linearize.h"
|
||||
#include <gu/map.h>
|
||||
#include <gu/fun.h>
|
||||
#include <gu/log.h>
|
||||
#include <gu/choice.h>
|
||||
#include <gu/seq.h>
|
||||
#include <gu/string.h>
|
||||
#include <gu/assert.h>
|
||||
#include <pgf/expr.h>
|
||||
|
||||
typedef GuStringMap PgfLinInfer;
|
||||
typedef GuSeq PgfProdSeq;
|
||||
|
||||
static GU_DEFINE_TYPE(PgfProdSeq, GuSeq, gu_type(PgfProduction));
|
||||
|
||||
typedef struct PgfLinInferEntry PgfLinInferEntry;
|
||||
|
||||
struct PgfLinInferEntry {
|
||||
PgfCCat* cat;
|
||||
PgfCncFun* fun;
|
||||
};
|
||||
|
||||
static GU_DEFINE_TYPE(
|
||||
PgfLinInferEntry, struct,
|
||||
GU_MEMBER_P(PgfLinInferEntry, cat, PgfCCat)
|
||||
// ,GU_MEMBER(PgfLinInferEntry, fun, ...)
|
||||
);
|
||||
|
||||
typedef GuBuf PgfLinInfers;
|
||||
static GU_DEFINE_TYPE(PgfLinInfers, GuBuf, gu_type(PgfLinInferEntry));
|
||||
|
||||
typedef GuIntMap PgfCncProds;
|
||||
static GU_DEFINE_TYPE(PgfCncProds, GuIntMap, gu_type(PgfProdSeq),
|
||||
&gu_null_seq);
|
||||
|
||||
typedef GuStringMap PgfLinProds;
|
||||
static GU_DEFINE_TYPE(PgfLinProds, GuStringMap, gu_ptr_type(PgfCncProds),
|
||||
&gu_null_struct);
|
||||
|
||||
|
||||
static GuHash
|
||||
pgf_lzr_cats_hash_fn(GuHasher* self, const void* p)
|
||||
{
|
||||
(void) self;
|
||||
PgfCCatIds* cats = *(PgfCCatIds* const*)p;
|
||||
size_t len = gu_list_length(cats);
|
||||
uintptr_t h = 0;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
h = 101 * h + (uintptr_t) gu_list_index(cats, i);
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
static bool
|
||||
pgf_lzr_cats_eq_fn(GuEquality* self, const void* p1, const void* p2)
|
||||
{
|
||||
(void) self;
|
||||
PgfCCatIds* cats1 = *(PgfCCatIds* const*) p1;
|
||||
PgfCCatIds* cats2 = *(PgfCCatIds* const*) p2;
|
||||
int len = gu_list_length(cats1);
|
||||
if (gu_list_length(cats2) != len) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < len; i++) {
|
||||
PgfCCat* cat1 = gu_list_index(cats1, i);
|
||||
PgfCCat* cat2 = gu_list_index(cats2, i);
|
||||
if (cat1 != cat2) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static GuHasher
|
||||
pgf_lzr_cats_hasher[1] = {
|
||||
{
|
||||
.eq = { pgf_lzr_cats_eq_fn },
|
||||
.hash = pgf_lzr_cats_hash_fn
|
||||
}
|
||||
};
|
||||
|
||||
typedef GuMap PgfInferMap;
|
||||
static GU_DEFINE_TYPE(PgfInferMap, GuMap,
|
||||
gu_ptr_type(PgfCCatIds), pgf_lzr_cats_hasher,
|
||||
gu_ptr_type(PgfLinInfers), &gu_null_struct);
|
||||
|
||||
typedef GuStringMap PgfFunIndices;
|
||||
static GU_DEFINE_TYPE(PgfFunIndices, GuStringMap, gu_ptr_type(PgfInferMap),
|
||||
&gu_null_struct);
|
||||
|
||||
typedef GuBuf PgfCCatBuf;
|
||||
static GU_DEFINE_TYPE(PgfCCatBuf, GuBuf, gu_ptr_type(PgfCCat));
|
||||
|
||||
typedef GuMap PgfCoerceIdx;
|
||||
static GU_DEFINE_TYPE(PgfCoerceIdx, GuMap,
|
||||
gu_type(PgfCCat), NULL,
|
||||
gu_ptr_type(PgfCCatBuf), &gu_null_struct);
|
||||
|
||||
struct PgfLzr {
|
||||
PgfConcr* cnc;
|
||||
GuPool* pool;
|
||||
PgfFunIndices* fun_indices;
|
||||
PgfCoerceIdx* coerce_idx;
|
||||
};
|
||||
|
||||
GU_DEFINE_TYPE(
|
||||
PgfLzr, struct,
|
||||
GU_MEMBER_P(PgfLzr, cnc, PgfConcr),
|
||||
GU_MEMBER_P(PgfLzr, fun_indices, PgfFunIndices),
|
||||
GU_MEMBER_P(PgfLzr, coerce_idx, PgfCoerceIdx));
|
||||
|
||||
|
||||
|
||||
|
||||
static void
|
||||
pgf_lzr_add_infer_entry(PgfLzr* lzr,
|
||||
PgfInferMap* infer_table,
|
||||
PgfCCat* cat,
|
||||
PgfProductionApply* papply)
|
||||
{
|
||||
PgfPArgs args = papply->args;
|
||||
size_t n_args = gu_seq_length(args);
|
||||
PgfCCatIds* arg_cats = gu_new_list(PgfCCatIds, lzr->pool, n_args);
|
||||
for (size_t i = 0; i < n_args; i++) {
|
||||
// XXX: What about the hypos in the args?
|
||||
gu_list_index(arg_cats, i) = gu_seq_get(args, PgfPArg, i).ccat;
|
||||
}
|
||||
gu_debug("%d,%d,%d -> %d, %s",
|
||||
n_args > 0 ? gu_list_index(arg_cats, 0)->fid : -1,
|
||||
n_args > 1 ? gu_list_index(arg_cats, 1)->fid : -1,
|
||||
n_args > 2 ? gu_list_index(arg_cats, 2)->fid : -1,
|
||||
cat->fid, papply->fun->fun);
|
||||
PgfLinInfers* entries =
|
||||
gu_map_get(infer_table, &arg_cats, PgfLinInfers*);
|
||||
if (!entries) {
|
||||
entries = gu_new_buf(PgfLinInferEntry, lzr->pool);
|
||||
gu_map_put(infer_table, &arg_cats, PgfLinInfers*, entries);
|
||||
} else {
|
||||
// XXX: arg_cats is duplicate, we ought to free it
|
||||
// Display warning?
|
||||
}
|
||||
|
||||
PgfLinInferEntry entry = {
|
||||
.cat = cat,
|
||||
.fun = papply->fun
|
||||
};
|
||||
gu_buf_push(entries, PgfLinInferEntry, entry);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
pgf_lzr_index(PgfLzr* lzr, PgfCCat* cat, PgfProduction prod)
|
||||
{
|
||||
void* data = gu_variant_data(prod);
|
||||
switch (gu_variant_tag(prod)) {
|
||||
case PGF_PRODUCTION_APPLY: {
|
||||
PgfProductionApply* papply = data;
|
||||
PgfInferMap* infer =
|
||||
gu_map_get(lzr->fun_indices, &papply->fun->fun,
|
||||
PgfInferMap*);
|
||||
gu_debug("index: %s -> %d", papply->fun->fun, cat->fid);
|
||||
if (!infer) {
|
||||
infer = gu_map_type_new(PgfInferMap, lzr->pool);
|
||||
gu_map_put(lzr->fun_indices,
|
||||
&papply->fun->fun, PgfInferMap*, infer);
|
||||
}
|
||||
pgf_lzr_add_infer_entry(lzr, infer, cat, papply);
|
||||
break;
|
||||
}
|
||||
case PGF_PRODUCTION_COERCE: {
|
||||
PgfProductionCoerce* pcoerce = data;
|
||||
PgfCCatBuf* cats = gu_map_get(lzr->coerce_idx, pcoerce->coerce,
|
||||
PgfCCatBuf*);
|
||||
if (!cats) {
|
||||
cats = gu_new_buf(PgfCCat*, lzr->pool);
|
||||
gu_map_put(lzr->coerce_idx,
|
||||
pcoerce->coerce, PgfCCatBuf*, cats);
|
||||
}
|
||||
gu_debug("coerce_idx: %d -> %d", pcoerce->coerce->fid, cat->fid);
|
||||
gu_buf_push(cats, PgfCCat*, cat);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// Display warning?
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pgf_lzr_index_ccat(PgfLzr* lzr, PgfCCat* cat)
|
||||
{
|
||||
gu_debug("ccat: %d", cat->fid);
|
||||
if (gu_seq_is_null(cat->prods)) {
|
||||
return;
|
||||
}
|
||||
size_t n_prods = gu_seq_length(cat->prods);
|
||||
for (size_t i = 0; i < n_prods; i++) {
|
||||
PgfProduction prod = gu_seq_get(cat->prods, PgfProduction, i);
|
||||
pgf_lzr_index(lzr, cat, prod);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
GuMapItor fn;
|
||||
PgfLzr* lzr;
|
||||
} PgfLzrIndexFn;
|
||||
|
||||
static void
|
||||
pgf_lzr_index_cnccat_cb(GuMapItor* fn, const void* key, void* value,
|
||||
GuExn* err)
|
||||
{
|
||||
(void) (key && err);
|
||||
PgfLzrIndexFn* clo = (PgfLzrIndexFn*) fn;
|
||||
PgfCncCat** cnccatp = value;
|
||||
PgfCncCat* cnccat = *cnccatp;
|
||||
gu_enter("-> cnccat: %s", cnccat->cid);
|
||||
int n_ccats = gu_list_length(cnccat->cats);
|
||||
for (int i = 0; i < n_ccats; i++) {
|
||||
PgfCCat* cat = gu_list_index(cnccat->cats, i);
|
||||
if (cat) {
|
||||
pgf_lzr_index_ccat(clo->lzr, cat);
|
||||
}
|
||||
}
|
||||
gu_exit("<-");
|
||||
}
|
||||
|
||||
|
||||
PgfLzr*
|
||||
pgf_new_lzr(PgfConcr* cnc, GuPool* pool)
|
||||
{
|
||||
PgfLzr* lzr = gu_new(PgfLzr, pool);
|
||||
lzr->cnc = cnc;
|
||||
lzr->pool = pool;
|
||||
lzr->fun_indices = gu_map_type_new(PgfFunIndices, pool);
|
||||
lzr->coerce_idx = gu_map_type_new(PgfCoerceIdx, pool);
|
||||
PgfLzrIndexFn clo = { { pgf_lzr_index_cnccat_cb }, lzr };
|
||||
gu_map_iter(cnc->cnccats, &clo.fn, NULL);
|
||||
size_t n_extras = gu_seq_length(cnc->extra_ccats);
|
||||
for (size_t i = 0; i < n_extras; i++) {
|
||||
PgfCCat* cat = gu_seq_get(cnc->extra_ccats, PgfCCat*, i);
|
||||
pgf_lzr_index_ccat(lzr, cat);
|
||||
}
|
||||
// TODO: prune productions with zero linearizations
|
||||
return lzr;
|
||||
}
|
||||
|
||||
typedef struct PgfLzn PgfLzn;
|
||||
|
||||
struct PgfLzn {
|
||||
PgfLzr* lzr;
|
||||
GuChoice* ch;
|
||||
PgfExpr expr;
|
||||
GuEnum en;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// PgfCncTree
|
||||
//
|
||||
|
||||
typedef enum {
|
||||
PGF_CNC_TREE_APP,
|
||||
PGF_CNC_TREE_LIT,
|
||||
} PgfCncTreeTag;
|
||||
|
||||
typedef struct PgfCncTreeApp PgfCncTreeApp;
|
||||
struct PgfCncTreeApp {
|
||||
PgfCncFun* fun;
|
||||
GuLength n_args;
|
||||
PgfCncTree args[];
|
||||
};
|
||||
|
||||
typedef struct PgfCncTreeLit PgfCncTreeLit;
|
||||
struct PgfCncTreeLit {
|
||||
PgfLiteral lit;
|
||||
};
|
||||
|
||||
|
||||
static PgfCCat*
|
||||
pgf_lzn_pick_supercat(PgfLzn* lzn, PgfCCat* cat)
|
||||
{
|
||||
gu_enter("->");
|
||||
while (true) {
|
||||
PgfCCatBuf* supers =
|
||||
gu_map_get(lzn->lzr->coerce_idx, cat, PgfCCatBuf*);
|
||||
if (!supers) {
|
||||
break;
|
||||
}
|
||||
gu_debug("n_supers: %d", gu_buf_length(supers));
|
||||
int ch = gu_choice_next(lzn->ch, gu_buf_length(supers) + 1);
|
||||
gu_debug("choice: %d", ch);
|
||||
if (ch == 0) {
|
||||
break;
|
||||
}
|
||||
cat = gu_buf_get(supers, PgfCCat*, ch - 1);
|
||||
}
|
||||
gu_exit("<- %d", cat->fid);
|
||||
return cat;
|
||||
}
|
||||
|
||||
static PgfCCat*
|
||||
pgf_lzn_infer(PgfLzn* lzn, PgfExpr expr, GuPool* pool, PgfCncTree* ctree_out);
|
||||
|
||||
static PgfCCat*
|
||||
pgf_lzn_infer_apply_try(PgfLzn* lzn, PgfApplication* appl,
|
||||
PgfInferMap* infer, GuChoiceMark* marks,
|
||||
PgfCCatIds* arg_cats, int* ip, int n_args,
|
||||
GuPool* pool, PgfCncTreeApp* app_out)
|
||||
{
|
||||
gu_enter("f: %s, *ip: %d, n_args: %d", appl->fun, *ip, n_args);
|
||||
PgfCCat* ret = NULL;
|
||||
while (*ip < n_args) {
|
||||
PgfCncTree* arg_treep =
|
||||
(app_out == NULL ? NULL : &app_out->args[*ip]);
|
||||
PgfCCat* arg_i =
|
||||
pgf_lzn_infer(lzn, appl->args[*ip], pool, arg_treep);
|
||||
if (arg_i == NULL) {
|
||||
goto finish;
|
||||
}
|
||||
arg_i = pgf_lzn_pick_supercat(lzn, arg_i);
|
||||
gu_list_index(arg_cats, *ip) = arg_i;
|
||||
marks[++*ip] = gu_choice_mark(lzn->ch);
|
||||
}
|
||||
PgfLinInfers* entries = gu_map_get(infer, &arg_cats, PgfLinInfers*);
|
||||
if (!entries) {
|
||||
goto finish;
|
||||
}
|
||||
size_t n_entries = gu_buf_length(entries);
|
||||
int e = gu_choice_next(lzn->ch, n_entries);
|
||||
gu_debug("entry %d of %d", e, n_entries);
|
||||
if (e < 0) {
|
||||
goto finish;
|
||||
}
|
||||
PgfLinInferEntry* entry = gu_buf_index(entries, PgfLinInferEntry, e);
|
||||
if (app_out != NULL) {
|
||||
app_out->fun = entry->fun;
|
||||
}
|
||||
ret = entry->cat;
|
||||
finish:
|
||||
gu_exit("fid: %d", ret ? ret->fid : -1);
|
||||
return ret;
|
||||
}
|
||||
typedef GuList(GuChoiceMark) PgfChoiceMarks;
|
||||
|
||||
static PgfCCat*
|
||||
pgf_lzn_infer_application(PgfLzn* lzn, PgfApplication* appl,
|
||||
GuPool* pool, PgfCncTree* ctree_out)
|
||||
{
|
||||
PgfInferMap* infer =
|
||||
gu_map_get(lzn->lzr->fun_indices, &appl->fun, PgfInferMap*);
|
||||
gu_enter("-> f: %s, n_args: %d", appl->fun, appl->n_args);
|
||||
if (infer == NULL) {
|
||||
gu_exit("<- couldn't find f");
|
||||
return NULL;
|
||||
}
|
||||
GuPool* tmp_pool = gu_new_pool();
|
||||
PgfCCat* ret = NULL;
|
||||
int n = appl->n_args;
|
||||
PgfCCatIds* arg_cats = gu_new_list(PgfCCatIds, tmp_pool, n);
|
||||
|
||||
PgfCncTreeApp* appt = NULL;
|
||||
if (ctree_out) {
|
||||
appt = gu_new_flex_variant(PGF_CNC_TREE_APP, PgfCncTreeApp,
|
||||
args, n, ctree_out, pool);
|
||||
appt->n_args = n;
|
||||
}
|
||||
|
||||
PgfChoiceMarks* marksl = gu_new_list(PgfChoiceMarks, tmp_pool, n + 1);
|
||||
GuChoiceMark* marks = gu_list_elems(marksl);
|
||||
int i = 0;
|
||||
marks[i] = gu_choice_mark(lzn->ch);
|
||||
while (true) {
|
||||
ret = pgf_lzn_infer_apply_try(lzn, appl, infer,
|
||||
marks, arg_cats,
|
||||
&i, n, pool, appt);
|
||||
if (ret != NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
do {
|
||||
--i;
|
||||
if (i < 0) {
|
||||
goto finish;
|
||||
}
|
||||
gu_choice_reset(lzn->ch, marks[i]);
|
||||
} while (!gu_choice_advance(lzn->ch));
|
||||
}
|
||||
finish:
|
||||
gu_pool_free(tmp_pool);
|
||||
gu_exit("<- fid: %d", ret ? ret->fid : -1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static PgfCCat*
|
||||
pgf_lzn_infer(PgfLzn* lzn, PgfExpr expr, GuPool* pool, PgfCncTree* ctree_out)
|
||||
{
|
||||
PgfCCat* ret = NULL;
|
||||
GuPool* tmp_pool = gu_new_pool();
|
||||
PgfApplication* appl = pgf_expr_unapply(expr, tmp_pool);
|
||||
if (appl != NULL) {
|
||||
ret = pgf_lzn_infer_application(lzn, appl, pool, ctree_out);
|
||||
} else {
|
||||
GuVariantInfo i = gu_variant_open(pgf_expr_unwrap(expr));
|
||||
switch (i.tag) {
|
||||
case PGF_EXPR_LIT: {
|
||||
PgfExprLit* elit = i.data;
|
||||
if (pool != NULL) {
|
||||
*ctree_out = gu_new_variant_i(
|
||||
pool, PGF_CNC_TREE_LIT,
|
||||
PgfCncTreeLit,
|
||||
.lit = elit->lit);
|
||||
}
|
||||
ret = pgf_literal_cat(elit->lit);
|
||||
}
|
||||
default:
|
||||
// XXX: should we do something here?
|
||||
break;
|
||||
}
|
||||
}
|
||||
gu_pool_free(tmp_pool);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static PgfCncTree
|
||||
pgf_lzn_next(PgfLzn* lzn, GuPool* pool)
|
||||
{
|
||||
// XXX: rewrite this whole mess
|
||||
PgfCncTree ctree = gu_null_variant;
|
||||
if (gu_variant_is_null(lzn->expr)) {
|
||||
return ctree;
|
||||
}
|
||||
PgfCCat* cat = NULL;
|
||||
GuChoiceMark mark = gu_choice_mark(lzn->ch);
|
||||
do {
|
||||
cat = pgf_lzn_infer(lzn, lzn->expr, NULL, NULL);
|
||||
gu_choice_reset(lzn->ch, mark);
|
||||
} while (!cat && gu_choice_advance(lzn->ch));
|
||||
|
||||
if (cat) {
|
||||
PgfCCat* cat2 = pgf_lzn_infer(lzn, lzn->expr, pool, &ctree);
|
||||
gu_assert(cat == cat2);
|
||||
gu_debug("fid: %d", cat->fid);
|
||||
gu_choice_reset(lzn->ch, mark);
|
||||
if (!gu_choice_advance(lzn->ch)) {
|
||||
lzn->expr = gu_null_variant;
|
||||
}
|
||||
}
|
||||
return ctree;
|
||||
}
|
||||
|
||||
static void
|
||||
pgf_cnc_tree_enum_next(GuEnum* self, void* to, GuPool* pool)
|
||||
{
|
||||
PgfLzn* lzn = gu_container(self, PgfLzn, en);
|
||||
PgfCncTree* toc = to;
|
||||
*toc = pgf_lzn_next(lzn, pool);
|
||||
}
|
||||
|
||||
PgfCncTreeEnum*
|
||||
pgf_lzr_concretize(PgfLzr* lzr, PgfExpr expr, GuPool* pool)
|
||||
{
|
||||
PgfLzn* lzn = gu_new(PgfLzn, pool);
|
||||
lzn->lzr = lzr;
|
||||
lzn->expr = expr;
|
||||
lzn->ch = gu_new_choice(pool);
|
||||
lzn->en.next = pgf_cnc_tree_enum_next;
|
||||
return &lzn->en;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
pgf_cnc_tree_dimension(PgfCncTree ctree)
|
||||
{
|
||||
GuVariantInfo cti = gu_variant_open(ctree);
|
||||
switch (cti.tag) {
|
||||
case PGF_CNC_TREE_LIT:
|
||||
return 1;
|
||||
case PGF_CNC_TREE_APP: {
|
||||
PgfCncTreeApp* fapp = cti.data;
|
||||
return fapp->fun->n_lins;
|
||||
}
|
||||
default:
|
||||
gu_impossible();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pgf_lzr_linearize(PgfLzr* lzr, PgfCncTree ctree, size_t lin_idx, PgfLinFuncs** fnsp)
|
||||
{
|
||||
PgfLinFuncs* fns = *fnsp;
|
||||
GuVariantInfo cti = gu_variant_open(ctree);
|
||||
|
||||
switch (cti.tag) {
|
||||
case PGF_CNC_TREE_LIT: {
|
||||
gu_require(lin_idx == 0);
|
||||
PgfCncTreeLit* flit = cti.data;
|
||||
if (fns->expr_literal) {
|
||||
fns->expr_literal(fnsp, flit->lit);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PGF_CNC_TREE_APP: {
|
||||
PgfCncTreeApp* fapp = cti.data;
|
||||
PgfCncFun* fun = fapp->fun;
|
||||
if (fns->expr_apply) {
|
||||
fns->expr_apply(fnsp, fun->fun, fapp->n_args);
|
||||
}
|
||||
gu_require(lin_idx < fun->n_lins);
|
||||
PgfSequence seq = fun->lins[lin_idx];
|
||||
size_t nsyms = gu_seq_length(seq);
|
||||
PgfSymbol* syms = gu_seq_data(seq);
|
||||
for (size_t i = 0; i < nsyms; i++) {
|
||||
PgfSymbol sym = syms[i];
|
||||
GuVariantInfo sym_i = gu_variant_open(sym);
|
||||
switch (sym_i.tag) {
|
||||
case PGF_SYMBOL_CAT:
|
||||
case PGF_SYMBOL_VAR:
|
||||
case PGF_SYMBOL_LIT: {
|
||||
PgfSymbolIdx* sidx = sym_i.data;
|
||||
gu_assert((unsigned) sidx->d < fapp->n_args);
|
||||
PgfCncTree argf = fapp->args[sidx->d];
|
||||
pgf_lzr_linearize(lzr, argf, sidx->r, fnsp);
|
||||
break;
|
||||
}
|
||||
case PGF_SYMBOL_KS: {
|
||||
PgfSymbolKS* ks = sym_i.data;
|
||||
if (fns->symbol_tokens) {
|
||||
fns->symbol_tokens(fnsp, ks->tokens);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PGF_SYMBOL_KP: {
|
||||
// TODO: correct prefix-dependencies
|
||||
PgfSymbolKP* kp = sym_i.data;
|
||||
if (fns->symbol_tokens) {
|
||||
fns->symbol_tokens(fnsp,
|
||||
kp->default_form);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
gu_impossible();
|
||||
}
|
||||
}
|
||||
break;
|
||||
} // case PGF_CNC_TREE_APP
|
||||
default:
|
||||
gu_impossible();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
typedef struct PgfSimpleLin PgfSimpleLin;
|
||||
|
||||
struct PgfSimpleLin {
|
||||
PgfLinFuncs* funcs;
|
||||
GuWriter* wtr;
|
||||
GuExn* err;
|
||||
};
|
||||
|
||||
static void
|
||||
pgf_file_lzn_symbol_tokens(PgfLinFuncs** funcs, PgfTokens toks)
|
||||
{
|
||||
PgfSimpleLin* flin = gu_container(funcs, PgfSimpleLin, funcs);
|
||||
if (!gu_ok(flin->err)) {
|
||||
return;
|
||||
}
|
||||
size_t len = gu_seq_length(toks);
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
PgfToken tok = gu_seq_get(toks, PgfToken, i);
|
||||
gu_string_write(tok, flin->wtr, flin->err);
|
||||
gu_putc(' ', flin->wtr, flin->err);
|
||||
}
|
||||
}
|
||||
|
||||
static PgfLinFuncs pgf_file_lin_funcs = {
|
||||
.symbol_tokens = pgf_file_lzn_symbol_tokens
|
||||
};
|
||||
|
||||
void
|
||||
pgf_lzr_linearize_simple(PgfLzr* lzr, PgfCncTree ctree,
|
||||
size_t lin_idx, GuWriter* wtr, GuExn* err)
|
||||
{
|
||||
PgfSimpleLin flin = {
|
||||
.funcs = &pgf_file_lin_funcs,
|
||||
.wtr = wtr,
|
||||
.err = err
|
||||
};
|
||||
pgf_lzr_linearize(lzr, ctree, lin_idx, &flin.funcs);
|
||||
}
|
||||
156
src/runtime/c/pgf/linearize.h
Normal file
156
src/runtime/c/pgf/linearize.h
Normal file
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright 2010-2011 University of Helsinki.
|
||||
*
|
||||
* This file is part of libpgf.
|
||||
*
|
||||
* Libpgf is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Libpgf 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 Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with libpgf. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <gu/type.h>
|
||||
#include <gu/dump.h>
|
||||
#include <gu/enum.h>
|
||||
#include <pgf/data.h>
|
||||
|
||||
/// Linearization of abstract syntax trees.
|
||||
/// @file
|
||||
|
||||
/** @name Linearizers
|
||||
*
|
||||
* Linearization begins by choosing a concrete category (#PgfConcr) for some
|
||||
* grammar, and creating a new linearizer (#PgfLzr) which can then be used to
|
||||
* linearize abstract syntax trees (#PgfExpr) of that grammar into the given
|
||||
* concrete category.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
||||
/// A linearizer.
|
||||
typedef struct PgfLzr PgfLzr;
|
||||
/**<
|
||||
*
|
||||
* A #PgfLzr object transforms abstract syntax trees of a PGF grammar
|
||||
* into sequences of token events for a single concrete category of
|
||||
* that grammar.
|
||||
*
|
||||
*/
|
||||
GU_DECLARE_TYPE(PgfLzr, struct);
|
||||
|
||||
|
||||
/// Create a new linearizer.
|
||||
PgfLzr*
|
||||
pgf_new_lzr(PgfConcr* cnc, GuPool* pool);
|
||||
/**<
|
||||
* @param cnc The concrete category to linearize to.
|
||||
*
|
||||
* @pool
|
||||
*
|
||||
* @return A new linearizer.
|
||||
*/
|
||||
|
||||
/** @}
|
||||
*
|
||||
* @name Enumerating concrete syntax trees
|
||||
*
|
||||
* Because of the \c variants construct in GF, there may be several
|
||||
* possible concrete syntax trees that correspond to a given abstract
|
||||
* syntax tree. These can be enumerated with #pgf_lzr_concretize and
|
||||
* #pgf_cnc_trees_next.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
||||
/// A concrete syntax tree
|
||||
typedef GuVariant PgfCncTree;
|
||||
|
||||
/// An enumeration of #PgfCncTree trees.
|
||||
typedef GuEnum PgfCncTreeEnum;
|
||||
|
||||
/// Begin enumerating concrete syntax variants.
|
||||
PgfCncTreeEnum*
|
||||
pgf_lzr_concretize(PgfLzr* lzr, PgfExpr expr, GuPool* pool);
|
||||
|
||||
/** @}
|
||||
*
|
||||
* @name Linearizing concrete syntax trees
|
||||
*
|
||||
* An individual concrete syntax tree has several different
|
||||
* linearizations, corresponding to the various fields and cases of
|
||||
* corresponding GF values. The number of these linearizations, called
|
||||
* the \e dimension of the tree, can be retrieved with
|
||||
* #pgf_cnc_tree_dimension.
|
||||
*
|
||||
* A single linearization of a concrete syntax tree is performed by
|
||||
* #pgf_lzr_linearize. The linearization is realized as a sequence of
|
||||
* events that are notified by calling the functions of a #PgfLinFuncs
|
||||
* structure that the client provides.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/// Callback functions for linearization.
|
||||
typedef struct PgfLinFuncs PgfLinFuncs;
|
||||
|
||||
struct PgfLinFuncs
|
||||
{
|
||||
/// Output tokens
|
||||
void (*symbol_tokens)(PgfLinFuncs** self, PgfTokens toks);
|
||||
|
||||
void (*symbol_expr)(PgfLinFuncs** self,
|
||||
int argno, PgfExpr expr, int lin_idx);
|
||||
|
||||
/// Begin application
|
||||
void (*expr_apply)(PgfLinFuncs** self, PgfCId cid, int n_args);
|
||||
|
||||
/// Output literal
|
||||
void (*expr_literal)(PgfLinFuncs** self, PgfLiteral lit);
|
||||
|
||||
void (*abort)(PgfLinFuncs** self);
|
||||
void (*finish)(PgfLinFuncs** self);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// Linearize a concrete syntax tree.
|
||||
void
|
||||
pgf_lzr_linearize(PgfLzr* lzr, PgfCncTree ctree, size_t lin_idx,
|
||||
PgfLinFuncs** fnsp);
|
||||
|
||||
|
||||
/// Linearize a concrete syntax tree as space-separated tokens.
|
||||
void
|
||||
pgf_lzr_linearize_simple(PgfLzr* lzr, PgfCncTree ctree,
|
||||
size_t lin_idx, GuWriter* wtr, GuExn* err);
|
||||
|
||||
|
||||
/// Return the dimension of a concrete syntax tree.
|
||||
int
|
||||
pgf_cnc_tree_dimension(PgfCncTree ctree);
|
||||
/**<
|
||||
* @param ctree A concrete syntax tree.
|
||||
*
|
||||
* @return The dimension of the tree, i.e. the number of different
|
||||
* linearizations the tree has.
|
||||
*/
|
||||
|
||||
//@}
|
||||
|
||||
|
||||
|
||||
extern GuTypeTable
|
||||
pgf_linearize_dump_table;
|
||||
|
||||
@@ -1,396 +0,0 @@
|
||||
#include "../pgf.h"
|
||||
#include "data.h"
|
||||
#include "panic.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static int readTag(FILE *f) {
|
||||
return getc(f);
|
||||
}
|
||||
|
||||
static int readInt16(FILE *f) {
|
||||
int x = getc(f);
|
||||
int y = getc(f);
|
||||
return ((x << 8) | y);
|
||||
}
|
||||
|
||||
static int readInt(FILE *f) {
|
||||
unsigned int x = (unsigned int) getc(f);
|
||||
if (x <= 0x7f)
|
||||
return (int) x;
|
||||
else {
|
||||
unsigned int y = (unsigned int) readInt(f);
|
||||
return (int) ((y << 7) | (x & 0x7f)) ;
|
||||
}
|
||||
}
|
||||
|
||||
static double readFloat(FILE *f) {
|
||||
double d;
|
||||
fread(&d, sizeof(d), 1, f);
|
||||
return d;
|
||||
}
|
||||
|
||||
static String readString(FILE *f) {
|
||||
int len = readInt(f);
|
||||
String str = (String) malloc(sizeof(struct _CId)+len*sizeof(unsigned int));
|
||||
str->len = len;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < len; i++) {
|
||||
int c = fgetc(f);
|
||||
str->chars[i] = c;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static CId readCId(FILE *f) {
|
||||
int len = readInt(f);
|
||||
CId cid = (CId) malloc(sizeof(struct _CId)+len*sizeof(char));
|
||||
cid->len = len;
|
||||
fread(&cid->chars, sizeof(char), len, f);
|
||||
return cid;
|
||||
}
|
||||
|
||||
static CIdList readCIdList(FILE *f) {
|
||||
int i;
|
||||
int count = readInt(f);
|
||||
CIdList list = (CIdList) malloc(sizeof(struct _CIdList)+count*sizeof(CId));
|
||||
|
||||
list->count = count;
|
||||
for (i = 0; i < count; i++) {
|
||||
list->names[i] = readCId(f);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
static Literal readLiteral(FILE *f) {
|
||||
int tag = readTag(f);
|
||||
switch (tag) {
|
||||
case LIT_STR:
|
||||
{
|
||||
LiteralStr lit = (LiteralStr) malloc(sizeof(struct _LiteralStr));
|
||||
lit->_.tag = tag;
|
||||
lit->val = readString(f);
|
||||
return ((Literal) lit);
|
||||
}
|
||||
case LIT_INT:
|
||||
{
|
||||
LiteralInt lit = (LiteralInt) malloc(sizeof(struct _LiteralInt));
|
||||
lit->_.tag = tag;
|
||||
lit->val = readInt(f);
|
||||
return ((Literal) lit);
|
||||
}
|
||||
case LIT_FLOAT:
|
||||
{
|
||||
LiteralFloat lit = (LiteralFloat) malloc(sizeof(struct _LiteralFloat));
|
||||
lit->_.tag = tag;
|
||||
lit->val = readFloat(f);
|
||||
return ((Literal) lit);
|
||||
}
|
||||
default:
|
||||
__pgf_panic("Unknown literal tag");
|
||||
}
|
||||
}
|
||||
|
||||
static Flags readFlags(FILE *f) {
|
||||
int i;
|
||||
int count = readInt(f);
|
||||
Flags flags = (Flags) malloc(sizeof(struct _Flags)+count*sizeof(struct _Flag));
|
||||
|
||||
flags->count = count;
|
||||
for (i = 0; i < count; i++) {
|
||||
flags->values[i].name = readCId(f);
|
||||
flags->values[i].value = readLiteral(f);
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static Context readContext(FILE *f);
|
||||
static Type readType(FILE *f);
|
||||
|
||||
static Expr readExpr(FILE *f) {
|
||||
int tag = readTag(f);
|
||||
|
||||
switch (tag) {
|
||||
case TAG_ABS:
|
||||
{
|
||||
ExprAbs e = (ExprAbs) malloc(sizeof(struct _ExprAbs));
|
||||
e->_.tag = tag;
|
||||
e->bt = readTag(f);
|
||||
e->var = readCId(f);
|
||||
e->body = readExpr(f);
|
||||
return ((Expr) e);
|
||||
}
|
||||
case TAG_APP:
|
||||
{
|
||||
ExprApp e = (ExprApp) malloc(sizeof(struct _ExprApp));
|
||||
e->_.tag = tag;
|
||||
e->left = readExpr(f);
|
||||
e->right = readExpr(f);
|
||||
return ((Expr) e);
|
||||
}
|
||||
case TAG_LIT:
|
||||
{
|
||||
ExprLit e = (ExprLit) malloc(sizeof(struct _ExprLit));
|
||||
e->_.tag = tag;
|
||||
e->lit = readLiteral(f);
|
||||
return ((Expr) e);
|
||||
}
|
||||
case TAG_MET:
|
||||
{
|
||||
ExprMeta e = (ExprMeta) malloc(sizeof(struct _ExprMeta));
|
||||
e->_.tag = tag;
|
||||
e->id = readInt(f);
|
||||
return ((Expr) e);
|
||||
}
|
||||
case TAG_FUN:
|
||||
{
|
||||
ExprFun e = (ExprFun) malloc(sizeof(struct _ExprFun));
|
||||
e->_.tag = tag;
|
||||
e->fun = readCId(f);
|
||||
return ((Expr) e);
|
||||
}
|
||||
case TAG_VAR:
|
||||
{
|
||||
ExprVar e = (ExprVar) malloc(sizeof(struct _ExprVar));
|
||||
e->_.tag = tag;
|
||||
e->index = readInt(f);
|
||||
return ((Expr) e);
|
||||
}
|
||||
case TAG_TYP:
|
||||
{
|
||||
ExprTyped e = (ExprTyped) malloc(sizeof(struct _ExprTyped));
|
||||
e->_.tag = tag;
|
||||
e->e = readExpr(f);
|
||||
e->ty = readType(f);
|
||||
return ((Expr) e);
|
||||
}
|
||||
case TAG_IMP:
|
||||
{
|
||||
ExprImplArg e = (ExprImplArg) malloc(sizeof(struct _ExprImplArg));
|
||||
e->_.tag = tag;
|
||||
e->e = readExpr(f);
|
||||
return ((Expr) e);
|
||||
}
|
||||
default:
|
||||
__pgf_panic("Unknown expression tag");
|
||||
}
|
||||
}
|
||||
|
||||
static Type readType(FILE *f) {
|
||||
Context hypos = readContext(f);
|
||||
CId cat = readCId(f);
|
||||
|
||||
int i;
|
||||
int count = readInt(f);
|
||||
Type ty = (Type) malloc(sizeof(struct _Type)+count*sizeof(Expr));
|
||||
|
||||
ty->hypos = hypos;
|
||||
ty->cat = cat;
|
||||
ty->nArgs = count;
|
||||
for (i = 0; i < count; i++) {
|
||||
ty->args[i] = readExpr(f);
|
||||
}
|
||||
|
||||
return ty;
|
||||
}
|
||||
|
||||
static void readHypo(FILE *f, Hypo h) {
|
||||
h->bt = readTag(f);
|
||||
h->var = readCId(f);
|
||||
h->ty = readType(f);
|
||||
}
|
||||
|
||||
static Context readContext(FILE *f) {
|
||||
int i;
|
||||
int size = readInt(f);
|
||||
Context ctxt = (Context) malloc(sizeof(struct _Context)+size*sizeof(struct _Hypo));
|
||||
|
||||
ctxt->size = size;
|
||||
for (i = 0; i < size; i++) {
|
||||
readHypo(f, &ctxt->hypos[i]);
|
||||
}
|
||||
|
||||
return ctxt;
|
||||
}
|
||||
|
||||
static Patt readPatt(FILE *f) {
|
||||
int tag = readTag(f);
|
||||
|
||||
switch (tag) {
|
||||
case TAG_PAPP:
|
||||
{
|
||||
CId fun = readCId(f);
|
||||
|
||||
int i;
|
||||
int count = readInt(f);
|
||||
PattApp p = (PattApp) malloc(sizeof(struct _PattApp)+count*sizeof(Patt));
|
||||
|
||||
p->_.tag = tag;
|
||||
p->fun = fun;
|
||||
p->args.count = count;
|
||||
for (i = 0; i < count; i++) {
|
||||
p->args.pats[i] = readPatt(f);
|
||||
}
|
||||
|
||||
return ((Patt) p);
|
||||
}
|
||||
case TAG_PVAR:
|
||||
{
|
||||
PattVar p = (PattVar) malloc(sizeof(struct _PattVar));
|
||||
p->_.tag = tag;
|
||||
p->var = readCId(f);
|
||||
return ((Patt) p);
|
||||
}
|
||||
case TAG_PAT:
|
||||
{
|
||||
PattAt p = (PattAt) malloc(sizeof(struct _PattAt));
|
||||
p->_.tag = tag;
|
||||
p->var = readCId(f);
|
||||
p->pat = readPatt(f);
|
||||
return ((Patt) p);
|
||||
}
|
||||
case TAG_PWILD:
|
||||
{
|
||||
PattWild p = (PattWild) malloc(sizeof(struct _PattWild));
|
||||
p->_.tag = tag;
|
||||
return ((Patt) p);
|
||||
}
|
||||
case TAG_PLIT:
|
||||
{
|
||||
PattLit p = (PattLit) malloc(sizeof(struct _PattLit));
|
||||
p->_.tag = tag;
|
||||
p->lit = readLiteral(f);
|
||||
return ((Patt) p);
|
||||
}
|
||||
case TAG_PIMP:
|
||||
{
|
||||
PattImplArg p = (PattImplArg) malloc(sizeof(struct _PattImplArg));
|
||||
p->_.tag = tag;
|
||||
p->pat = readPatt(f);
|
||||
return ((Patt) p);
|
||||
}
|
||||
case TAG_PTILDE:
|
||||
{
|
||||
PattTilde p = (PattTilde) malloc(sizeof(struct _PattTilde));
|
||||
p->_.tag = tag;
|
||||
p->e = readExpr(f);
|
||||
return ((Patt) p);
|
||||
}
|
||||
default:
|
||||
__pgf_panic("Unknown pattern tag");
|
||||
}
|
||||
}
|
||||
|
||||
static Patts readPatts(FILE *f) {
|
||||
int i;
|
||||
int count = readInt(f);
|
||||
Patts pats = (Patts) malloc(sizeof(struct _Patts)+count*sizeof(Patt));
|
||||
|
||||
pats->count = count;
|
||||
for (i = 0; i < count; i++) {
|
||||
pats->pats[i] = readPatt(f);
|
||||
}
|
||||
|
||||
return pats;
|
||||
}
|
||||
|
||||
static Equations readEquations(FILE *f) {
|
||||
int i;
|
||||
int count = readInt(f);
|
||||
Equations equs = (Equations) malloc(sizeof(struct _Equations)+count*sizeof(struct _Equation));
|
||||
|
||||
equs->count = count;
|
||||
for (i = 0; i < count; i++) {
|
||||
equs->equs[i].lhs = readPatts(f);
|
||||
equs->equs[i].rhs = readExpr(f);
|
||||
}
|
||||
|
||||
return equs;
|
||||
}
|
||||
|
||||
static void readAbsFun(FILE *f, AbsFun fun) {
|
||||
fun->name = readCId(f);
|
||||
fun->ty = readType(f);
|
||||
fun->arrity = readInt(f);
|
||||
if (readTag(f) != 0)
|
||||
fun->equs = readEquations(f);
|
||||
else
|
||||
fun->equs = NULL;
|
||||
}
|
||||
|
||||
static AbsFuns readAbsFuns(FILE *f) {
|
||||
int i;
|
||||
int count = readInt(f);
|
||||
AbsFuns funs = (AbsFuns) malloc(sizeof(struct _AbsFuns)+count*sizeof(struct _AbsFun));
|
||||
|
||||
funs->count = count;
|
||||
for (i = 0; i < count; i++) {
|
||||
readAbsFun(f, &funs->lst[i]);
|
||||
}
|
||||
|
||||
return funs;
|
||||
}
|
||||
|
||||
static void readAbsCat(FILE *f, AbsCat cat) {
|
||||
cat->name = readCId(f);
|
||||
cat->hypos = readContext(f);
|
||||
cat->funs = readCIdList(f);
|
||||
}
|
||||
|
||||
static AbsCats readAbsCats(FILE *f) {
|
||||
int i;
|
||||
int count = readInt(f);
|
||||
AbsCats cats = (AbsCats) malloc(sizeof(struct _AbsCats)+count*sizeof(struct _AbsCat));
|
||||
|
||||
cats->count = count;
|
||||
for (i = 0; i < count; i++) {
|
||||
readAbsCat(f, &cats->lst[i]);
|
||||
}
|
||||
|
||||
return cats;
|
||||
}
|
||||
|
||||
static void readAbstr(FILE *f, Abstract abstr) {
|
||||
abstr->name = readCId(f);
|
||||
abstr->flags = readFlags(f);
|
||||
abstr->funs = readAbsFuns(f);
|
||||
abstr->cats = readAbsCats(f);
|
||||
}
|
||||
|
||||
static void readConcr(FILE *f, Concrete concr) {
|
||||
concr->name = readCId(f);
|
||||
concr->flags = readFlags(f);
|
||||
}
|
||||
|
||||
PGF readPGF(char *filename) {
|
||||
FILE *f = fopen(filename, "rb");
|
||||
if (f == NULL)
|
||||
return NULL;
|
||||
|
||||
int maj_ver = readInt16(f);
|
||||
int min_ver = readInt16(f);
|
||||
|
||||
Flags flags = readFlags(f);
|
||||
|
||||
struct _Abstract abstr;
|
||||
readAbstr(f, &abstr);
|
||||
|
||||
int nConcr = readInt(f);
|
||||
PGF pgf = (PGF) malloc(sizeof(struct _PGF)+sizeof(Concrete)*nConcr);
|
||||
|
||||
pgf->flags = flags;
|
||||
pgf->abstract = abstr;
|
||||
pgf->nConcr = nConcr;
|
||||
|
||||
int i;
|
||||
// for (i = 0; i < nConcr; i++) {
|
||||
// readConcr(f, &pgf->concretes[i]);
|
||||
// }
|
||||
|
||||
fclose(f);
|
||||
return pgf;
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
#include "panic.h"
|
||||
#include <stdio.h>
|
||||
|
||||
void __pgf_panic(char *msg) {
|
||||
printf("%s\n",msg);
|
||||
fflush(stdout);
|
||||
exit(1);
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
#ifndef PGF_PANIC_H
|
||||
#define PGF_PANIC_H
|
||||
|
||||
void __pgf_panic(char *msg);
|
||||
|
||||
#endif
|
||||
697
src/runtime/c/pgf/parser.c
Normal file
697
src/runtime/c/pgf/parser.c
Normal file
@@ -0,0 +1,697 @@
|
||||
#include <pgf/parser.h>
|
||||
#include <gu/choice.h>
|
||||
#include <gu/seq.h>
|
||||
#include <gu/assert.h>
|
||||
#include <gu/log.h>
|
||||
|
||||
typedef struct PgfItem PgfItem;
|
||||
|
||||
enum {
|
||||
PGF_FID_SYNTHETIC = -999
|
||||
};
|
||||
|
||||
typedef GuBuf PgfItemBuf;
|
||||
typedef GuList(PgfItemBuf*) PgfItemBufs;
|
||||
|
||||
|
||||
|
||||
// GuString -> PgfItemBuf*
|
||||
typedef GuMap PgfTransitions;
|
||||
|
||||
typedef GuBuf PgfCCatBuf;
|
||||
|
||||
struct PgfParser {
|
||||
PgfConcr* concr;
|
||||
};
|
||||
|
||||
struct PgfParse {
|
||||
PgfParser* parser;
|
||||
PgfTransitions* transitions;
|
||||
PgfCCatBuf* completed;
|
||||
};
|
||||
|
||||
typedef struct PgfParseResult PgfParseResult;
|
||||
|
||||
struct PgfParseResult {
|
||||
PgfCCatBuf* completed;
|
||||
GuChoice* choice;
|
||||
PgfExprEnum en;
|
||||
};
|
||||
|
||||
typedef struct PgfItemBase PgfItemBase;
|
||||
|
||||
struct PgfItemBase {
|
||||
PgfItemBuf* conts;
|
||||
PgfCCat* ccat;
|
||||
PgfProduction prod;
|
||||
unsigned short lin_idx;
|
||||
};
|
||||
|
||||
struct PgfItem {
|
||||
PgfItemBase* base;
|
||||
PgfPArgs args;
|
||||
PgfSymbol curr_sym;
|
||||
uint16_t seq_idx;
|
||||
uint8_t tok_idx;
|
||||
uint8_t alt;
|
||||
};
|
||||
|
||||
typedef GuMap PgfContsMap;
|
||||
|
||||
|
||||
static GU_DEFINE_TYPE(PgfItemBuf, abstract, _);
|
||||
static GU_DEFINE_TYPE(PgfItemBufs, abstract, _);
|
||||
static GU_DEFINE_TYPE(PgfContsMap, GuMap,
|
||||
gu_type(PgfCCat), NULL,
|
||||
gu_ptr_type(PgfItemBufs), &gu_null_struct);
|
||||
|
||||
static GU_DEFINE_TYPE(PgfGenCatMap, GuMap,
|
||||
gu_type(PgfItemBuf), NULL,
|
||||
gu_ptr_type(PgfCCat), &gu_null_struct);
|
||||
|
||||
static GU_DEFINE_TYPE(PgfTransitions, GuStringMap,
|
||||
gu_ptr_type(PgfItemBuf), &gu_null_struct);
|
||||
|
||||
typedef GuMap PgfGenCatMap;
|
||||
|
||||
typedef struct PgfParsing PgfParsing;
|
||||
|
||||
struct PgfParsing {
|
||||
PgfParse* parse;
|
||||
GuPool* pool;
|
||||
PgfContsMap* conts_map;
|
||||
PgfGenCatMap* generated_cats;
|
||||
};
|
||||
|
||||
static void
|
||||
pgf_parsing_add_transition(PgfParsing* parsing, PgfToken tok, PgfItem* item)
|
||||
{
|
||||
gu_debug("%s -> %p", tok, item);
|
||||
PgfTransitions* tmap = parsing->parse->transitions;
|
||||
PgfItemBuf* items = gu_map_get(tmap, &tok, PgfItemBuf*);
|
||||
if (!items) {
|
||||
items = gu_new_buf(PgfItem*, parsing->pool);
|
||||
gu_map_put(tmap, &tok, PgfItemBuf*, items);
|
||||
}
|
||||
gu_buf_push(items, PgfItem*, item);
|
||||
}
|
||||
|
||||
static PgfItemBufs*
|
||||
pgf_parsing_get_contss(PgfParsing* parsing, PgfCCat* cat)
|
||||
{
|
||||
PgfItemBufs* contss = gu_map_get(parsing->conts_map, cat, PgfItemBufs*);
|
||||
if (!contss) {
|
||||
size_t n_lins = cat->cnccat->n_lins;
|
||||
contss = gu_new_list(PgfItemBufs, parsing->pool, n_lins);
|
||||
for (size_t i = 0; i < n_lins; i++) {
|
||||
gu_list_index(contss, i) = NULL;
|
||||
}
|
||||
gu_map_put(parsing->conts_map, cat, PgfItemBufs*, contss);
|
||||
}
|
||||
return contss;
|
||||
}
|
||||
|
||||
|
||||
static PgfItemBuf*
|
||||
pgf_parsing_get_conts(PgfParsing* parsing, PgfCCat* cat, size_t lin_idx)
|
||||
{
|
||||
gu_require(lin_idx < cat->cnccat->n_lins);
|
||||
PgfItemBufs* contss = pgf_parsing_get_contss(parsing, cat);
|
||||
PgfItemBuf* conts = gu_list_index(contss, lin_idx);
|
||||
if (!conts) {
|
||||
conts = gu_new_buf(PgfItem*, parsing->pool);
|
||||
gu_list_index(contss, lin_idx) = conts;
|
||||
}
|
||||
return conts;
|
||||
}
|
||||
|
||||
static PgfCCat*
|
||||
pgf_parsing_create_completed(PgfParsing* parsing, PgfItemBuf* conts,
|
||||
PgfCncCat* cnccat)
|
||||
{
|
||||
PgfCCat* cat = gu_new(PgfCCat, parsing->pool);
|
||||
cat->cnccat = cnccat;
|
||||
cat->fid = PGF_FID_SYNTHETIC;
|
||||
cat->prods = gu_buf_seq(gu_new_buf(PgfProduction, parsing->pool));
|
||||
gu_map_put(parsing->generated_cats, conts, PgfCCat*, cat);
|
||||
return cat;
|
||||
}
|
||||
|
||||
static PgfCCat*
|
||||
pgf_parsing_get_completed(PgfParsing* parsing, PgfItemBuf* conts)
|
||||
{
|
||||
return gu_map_get(parsing->generated_cats, conts, PgfCCat*);
|
||||
}
|
||||
|
||||
static PgfSymbol
|
||||
pgf_item_base_symbol(PgfItemBase* ibase, size_t seq_idx, GuPool* pool)
|
||||
{
|
||||
GuVariantInfo i = gu_variant_open(ibase->prod);
|
||||
switch (i.tag) {
|
||||
case PGF_PRODUCTION_APPLY: {
|
||||
PgfProductionApply* papp = i.data;
|
||||
PgfCncFun* fun = papp->fun;
|
||||
gu_assert(ibase->lin_idx < fun->n_lins);
|
||||
PgfSequence seq = fun->lins[ibase->lin_idx];
|
||||
gu_assert(seq_idx <= gu_seq_length(seq));
|
||||
if (seq_idx == gu_seq_length(seq)) {
|
||||
return gu_null_variant;
|
||||
} else {
|
||||
return gu_seq_get(seq, PgfSymbol, seq_idx);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PGF_PRODUCTION_COERCE: {
|
||||
gu_assert(seq_idx <= 1);
|
||||
if (seq_idx == 1) {
|
||||
return gu_null_variant;
|
||||
} else {
|
||||
return gu_new_variant_i(pool, PGF_SYMBOL_CAT,
|
||||
PgfSymbolCat,
|
||||
.d = 0, .r = ibase->lin_idx);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
gu_impossible();
|
||||
}
|
||||
return gu_null_variant;
|
||||
}
|
||||
|
||||
static PgfItem*
|
||||
pgf_new_item(PgfItemBase* base, GuPool* pool)
|
||||
{
|
||||
PgfItem* item = gu_new(PgfItem, pool);
|
||||
GuVariantInfo pi = gu_variant_open(base->prod);
|
||||
switch (pi.tag) {
|
||||
case PGF_PRODUCTION_APPLY: {
|
||||
PgfProductionApply* papp = pi.data;
|
||||
item->args = papp->args;
|
||||
break;
|
||||
}
|
||||
case PGF_PRODUCTION_COERCE: {
|
||||
PgfProductionCoerce* pcoerce = pi.data;
|
||||
item->args = gu_new_seq(PgfPArg, 1, pool);
|
||||
PgfPArg* parg = gu_seq_index(item->args, PgfPArg, 0);
|
||||
parg->hypos = NULL;
|
||||
parg->ccat = pcoerce->coerce;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
gu_impossible();
|
||||
}
|
||||
item->base = base;
|
||||
item->curr_sym = pgf_item_base_symbol(item->base, 0, pool);
|
||||
item->seq_idx = 0;
|
||||
item->tok_idx = 0;
|
||||
item->alt = 0;
|
||||
return item;
|
||||
}
|
||||
|
||||
static PgfItem*
|
||||
pgf_item_copy(PgfItem* item, GuPool* pool)
|
||||
{
|
||||
PgfItem* copy = gu_new(PgfItem, pool);
|
||||
memcpy(copy, item, sizeof(PgfItem));
|
||||
return copy;
|
||||
}
|
||||
|
||||
static void
|
||||
pgf_item_advance(PgfItem* item, GuPool* pool)
|
||||
{
|
||||
item->seq_idx++;
|
||||
item->curr_sym = pgf_item_base_symbol(item->base, item->seq_idx, pool);
|
||||
}
|
||||
|
||||
static void
|
||||
pgf_parsing_item(PgfParsing* parsing, PgfItem* item);
|
||||
|
||||
static void
|
||||
pgf_parsing_combine(PgfParsing* parsing, PgfItem* cont, PgfCCat* cat)
|
||||
{
|
||||
if (cont == NULL) {
|
||||
gu_buf_push(parsing->parse->completed, PgfCCat*, cat);
|
||||
return;
|
||||
}
|
||||
PgfItem* item = pgf_item_copy(cont, parsing->pool);
|
||||
size_t nargs = gu_seq_length(cont->args);
|
||||
item->args = gu_new_seq(PgfPArg, nargs, parsing->pool);
|
||||
memcpy(gu_seq_data(item->args), gu_seq_data(cont->args),
|
||||
nargs * sizeof(PgfPArg));
|
||||
gu_assert(gu_variant_tag(item->curr_sym) == PGF_SYMBOL_CAT);
|
||||
PgfSymbolCat* pcat = gu_variant_data(cont->curr_sym);
|
||||
gu_seq_set(item->args, PgfPArg, pcat->d,
|
||||
((PgfPArg) { .hypos = NULL, .ccat = cat }));
|
||||
pgf_item_advance(item, parsing->pool);
|
||||
pgf_parsing_item(parsing, item);
|
||||
}
|
||||
|
||||
static void
|
||||
pgf_parsing_production(PgfParsing* parsing, PgfCCat* cat, size_t lin_idx,
|
||||
PgfProduction prod, PgfItemBuf* conts)
|
||||
{
|
||||
PgfItemBase* base = gu_new(PgfItemBase, parsing->pool);
|
||||
base->ccat = cat;
|
||||
base->lin_idx = lin_idx;
|
||||
base->prod = prod;
|
||||
base->conts = conts;
|
||||
PgfItem* item = pgf_new_item(base, parsing->pool);
|
||||
pgf_parsing_item(parsing, item);
|
||||
}
|
||||
|
||||
static void
|
||||
pgf_parsing_complete(PgfParsing* parsing, PgfItem* item)
|
||||
{
|
||||
GuVariantInfo i = gu_variant_open(item->base->prod);
|
||||
PgfProduction prod = gu_null_variant;
|
||||
switch (i.tag) {
|
||||
case PGF_PRODUCTION_APPLY: {
|
||||
PgfProductionApply* papp = i.data;
|
||||
PgfProductionApply* new_papp =
|
||||
gu_new_variant(PGF_PRODUCTION_APPLY,
|
||||
PgfProductionApply,
|
||||
&prod, parsing->pool);
|
||||
new_papp->fun = papp->fun;
|
||||
new_papp->args = item->args;
|
||||
break;
|
||||
}
|
||||
case PGF_PRODUCTION_COERCE: {
|
||||
PgfProductionCoerce* new_pcoerce =
|
||||
gu_new_variant(PGF_PRODUCTION_COERCE,
|
||||
PgfProductionCoerce,
|
||||
&prod, parsing->pool);
|
||||
PgfPArg* parg = gu_seq_index(item->args, PgfPArg, 0);
|
||||
gu_assert(!parg->hypos || !parg->hypos->len);
|
||||
new_pcoerce->coerce = parg->ccat;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
gu_impossible();
|
||||
}
|
||||
PgfItemBuf* conts = item->base->conts;
|
||||
PgfCCat* cat = pgf_parsing_get_completed(parsing, conts);
|
||||
if (cat != NULL) {
|
||||
// The category has already been created. If it has also been
|
||||
// predicted already, then process a new item for this production.
|
||||
PgfItemBufs* contss = pgf_parsing_get_contss(parsing, cat);
|
||||
size_t n_contss = gu_list_length(contss);
|
||||
for (size_t i = 0; i < n_contss; i++) {
|
||||
PgfItemBuf* conts2 = gu_list_index(contss, i);
|
||||
/* If there are continuations for
|
||||
* linearization index i, then (cat, i) has
|
||||
* already been predicted. Add the new
|
||||
* production immediately to the agenda,
|
||||
* i.e. process it. */
|
||||
if (conts2) {
|
||||
pgf_parsing_production(parsing, cat, i,
|
||||
prod, conts2);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cat = pgf_parsing_create_completed(parsing, conts,
|
||||
item->base->ccat->cnccat);
|
||||
size_t n_conts = gu_buf_length(conts);
|
||||
for (size_t i = 0; i < n_conts; i++) {
|
||||
PgfItem* cont = gu_buf_get(conts, PgfItem*, i);
|
||||
pgf_parsing_combine(parsing, cont, cat);
|
||||
}
|
||||
}
|
||||
GuBuf* prodbuf = gu_seq_buf(cat->prods);
|
||||
gu_buf_push(prodbuf, PgfProduction, prod);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
pgf_parsing_predict(PgfParsing* parsing, PgfItem* item,
|
||||
PgfCCat* cat, size_t lin_idx)
|
||||
{
|
||||
gu_enter("-> cat: %d", cat->fid);
|
||||
if (gu_seq_is_null(cat->prods)) {
|
||||
// Empty category
|
||||
return;
|
||||
}
|
||||
PgfItemBuf* conts = pgf_parsing_get_conts(parsing, cat, lin_idx);
|
||||
gu_buf_push(conts, PgfItem*, item);
|
||||
if (gu_buf_length(conts) == 1) {
|
||||
/* First time we encounter this linearization
|
||||
* of this category at the current position,
|
||||
* so predict it. */
|
||||
PgfProductionSeq prods = cat->prods;
|
||||
size_t n_prods = gu_seq_length(prods);
|
||||
for (size_t i = 0; i < n_prods; i++) {
|
||||
PgfProduction prod =
|
||||
gu_seq_get(prods, PgfProduction, i);
|
||||
pgf_parsing_production(parsing, cat, lin_idx,
|
||||
prod, conts);
|
||||
}
|
||||
} else {
|
||||
/* If it has already been completed, combine. */
|
||||
PgfCCat* completed =
|
||||
pgf_parsing_get_completed(parsing, conts);
|
||||
if (completed) {
|
||||
pgf_parsing_combine(parsing, item, completed);
|
||||
}
|
||||
}
|
||||
gu_exit(NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
pgf_parsing_symbol(PgfParsing* parsing, PgfItem* item, PgfSymbol sym) {
|
||||
switch (gu_variant_tag(sym)) {
|
||||
case PGF_SYMBOL_CAT: {
|
||||
PgfSymbolCat* scat = gu_variant_data(sym);
|
||||
PgfPArg* parg = gu_seq_index(item->args, PgfPArg, scat->d);
|
||||
gu_assert(!parg->hypos || !parg->hypos->len);
|
||||
pgf_parsing_predict(parsing, item, parg->ccat, scat->r);
|
||||
break;
|
||||
}
|
||||
case PGF_SYMBOL_KS: {
|
||||
PgfSymbolKS* sks = gu_variant_data(sym);
|
||||
gu_assert(item->tok_idx < gu_seq_length(sks->tokens));
|
||||
PgfToken tok =
|
||||
gu_seq_get(sks->tokens, PgfToken, item->tok_idx);
|
||||
pgf_parsing_add_transition(parsing, tok, item);
|
||||
break;
|
||||
}
|
||||
case PGF_SYMBOL_KP: {
|
||||
PgfSymbolKP* skp = gu_variant_data(sym);
|
||||
size_t idx = item->tok_idx;
|
||||
uint8_t alt = item->alt;
|
||||
gu_assert(idx < gu_seq_length(skp->default_form));
|
||||
if (idx == 0) {
|
||||
PgfToken tok = gu_seq_get(skp->default_form, PgfToken, 0);
|
||||
pgf_parsing_add_transition(parsing, tok, item);
|
||||
for (size_t i = 0; i < skp->n_forms; i++) {
|
||||
PgfTokens toks = skp->forms[i].form;
|
||||
PgfTokens toks2 = skp->default_form;
|
||||
// XXX: do nubbing properly
|
||||
bool skip = pgf_tokens_equal(toks, toks2);
|
||||
for (size_t j = 0; j < i; j++) {
|
||||
PgfTokens toks2 = skp->forms[j].form;
|
||||
skip |= pgf_tokens_equal(toks, toks2);
|
||||
}
|
||||
if (skip) {
|
||||
continue;
|
||||
}
|
||||
PgfToken tok = gu_seq_get(toks, PgfToken, 0);
|
||||
pgf_parsing_add_transition(parsing, tok, item);
|
||||
}
|
||||
} else if (alt == 0) {
|
||||
PgfToken tok =
|
||||
gu_seq_get(skp->default_form, PgfToken, idx);
|
||||
pgf_parsing_add_transition(parsing, tok, item);
|
||||
} else {
|
||||
gu_assert(alt <= skp->n_forms);
|
||||
PgfToken tok = gu_seq_get(skp->forms[alt - 1].form,
|
||||
PgfToken, idx);
|
||||
pgf_parsing_add_transition(parsing, tok, item);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PGF_SYMBOL_LIT:
|
||||
// XXX TODO proper support
|
||||
break;
|
||||
case PGF_SYMBOL_VAR:
|
||||
// XXX TODO proper support
|
||||
break;
|
||||
default:
|
||||
gu_impossible();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pgf_parsing_item(PgfParsing* parsing, PgfItem* item)
|
||||
{
|
||||
GuVariantInfo i = gu_variant_open(item->base->prod);
|
||||
switch (i.tag) {
|
||||
case PGF_PRODUCTION_APPLY: {
|
||||
PgfProductionApply* papp = i.data;
|
||||
PgfCncFun* fun = papp->fun;
|
||||
PgfSequence seq = fun->lins[item->base->lin_idx];
|
||||
if (item->seq_idx == gu_seq_length(seq)) {
|
||||
pgf_parsing_complete(parsing, item);
|
||||
} else {
|
||||
PgfSymbol sym =
|
||||
gu_seq_get(seq, PgfSymbol, item->seq_idx);
|
||||
pgf_parsing_symbol(parsing, item, sym);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PGF_PRODUCTION_COERCE: {
|
||||
PgfProductionCoerce* pcoerce = i.data;
|
||||
switch (item->seq_idx) {
|
||||
case 0:
|
||||
pgf_parsing_predict(parsing, item,
|
||||
pcoerce->coerce,
|
||||
item->base->lin_idx);
|
||||
break;
|
||||
case 1:
|
||||
pgf_parsing_complete(parsing, item);
|
||||
break;
|
||||
default:
|
||||
gu_impossible();
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
gu_impossible();
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
pgf_parsing_scan_toks(PgfParsing* parsing, PgfItem* old_item,
|
||||
PgfToken tok, int alt, PgfTokens toks)
|
||||
{
|
||||
gu_assert(old_item->tok_idx < gu_seq_length(toks));
|
||||
if (!gu_string_eq(gu_seq_get(toks, PgfToken, old_item->tok_idx),
|
||||
tok)) {
|
||||
return false;
|
||||
}
|
||||
PgfItem* item = pgf_item_copy(old_item, parsing->pool);
|
||||
item->tok_idx++;
|
||||
item->alt = alt;
|
||||
if (item->tok_idx == gu_seq_length(toks)) {
|
||||
item->tok_idx = 0;
|
||||
pgf_item_advance(item, parsing->pool);
|
||||
}
|
||||
pgf_parsing_item(parsing, item);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
pgf_parsing_scan(PgfParsing* parsing, PgfItem* item, PgfToken tok)
|
||||
{
|
||||
bool succ = false;
|
||||
GuVariantInfo i = gu_variant_open(item->curr_sym);
|
||||
switch (i.tag) {
|
||||
case PGF_SYMBOL_KS: {
|
||||
PgfSymbolKS* ks = i.data;
|
||||
succ = pgf_parsing_scan_toks(parsing, item, tok, 0,
|
||||
ks->tokens);
|
||||
break;
|
||||
}
|
||||
case PGF_SYMBOL_KP: {
|
||||
PgfSymbolKP* kp = i.data;
|
||||
size_t alt = item->alt;
|
||||
if (item->tok_idx == 0) {
|
||||
succ = pgf_parsing_scan_toks(parsing, item, tok, 0,
|
||||
kp->default_form);
|
||||
for (size_t i = 0; i < kp->n_forms; i++) {
|
||||
// XXX: do nubbing properly
|
||||
PgfTokens toks = kp->forms[i].form;
|
||||
PgfTokens toks2 = kp->default_form;
|
||||
bool skip = pgf_tokens_equal(toks, toks2);
|
||||
for (size_t j = 0; j < i; j++) {
|
||||
PgfTokens toks2 = kp->forms[j].form;
|
||||
skip |= pgf_tokens_equal(toks, toks2);
|
||||
}
|
||||
if (!skip) {
|
||||
succ |= pgf_parsing_scan_toks(
|
||||
parsing, item, tok, i + 1,
|
||||
kp->forms[i].form);
|
||||
}
|
||||
}
|
||||
} else if (alt == 0) {
|
||||
succ = pgf_parsing_scan_toks(parsing, item, tok, 0,
|
||||
kp->default_form);
|
||||
} else {
|
||||
gu_assert(alt <= kp->n_forms);
|
||||
succ = pgf_parsing_scan_toks(parsing, item, tok,
|
||||
alt, kp->forms[alt - 1].form);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
gu_impossible();
|
||||
}
|
||||
gu_assert(succ);
|
||||
}
|
||||
|
||||
|
||||
static PgfParsing*
|
||||
pgf_new_parsing(PgfParse* parse, GuPool* parse_pool, GuPool* out_pool)
|
||||
{
|
||||
PgfParsing* parsing = gu_new(PgfParsing, out_pool);
|
||||
parsing->parse = parse;
|
||||
parsing->generated_cats = gu_map_type_new(PgfGenCatMap, out_pool);
|
||||
parsing->conts_map = gu_map_type_new(PgfContsMap, out_pool);
|
||||
parsing->pool = parse_pool;
|
||||
return parsing;
|
||||
}
|
||||
|
||||
static PgfParse*
|
||||
pgf_new_parse(PgfParser* parser, GuPool* pool)
|
||||
{
|
||||
PgfParse* parse = gu_new(PgfParse, pool);
|
||||
parse->parser = parser;
|
||||
parse->transitions = gu_map_type_new(PgfTransitions, pool);
|
||||
parse->completed = gu_new_buf(PgfCCat*, pool);
|
||||
return parse;
|
||||
}
|
||||
|
||||
PgfParse*
|
||||
pgf_parse_token(PgfParse* parse, PgfToken tok, GuPool* pool)
|
||||
{
|
||||
PgfItemBuf* agenda =
|
||||
gu_map_get(parse->transitions, &tok, PgfItemBuf*);
|
||||
if (!agenda) {
|
||||
return NULL;
|
||||
}
|
||||
PgfParse* next_parse = pgf_new_parse(parse->parser, pool);
|
||||
GuPool* tmp_pool = gu_new_pool();
|
||||
PgfParsing* parsing = pgf_new_parsing(next_parse, pool, tmp_pool);
|
||||
size_t n_items = gu_buf_length(agenda);
|
||||
for (size_t i = 0; i < n_items; i++) {
|
||||
PgfItem* item = gu_buf_get(agenda, PgfItem*, i);
|
||||
pgf_parsing_scan(parsing, item, tok);
|
||||
}
|
||||
gu_pool_free(tmp_pool);
|
||||
return next_parse;
|
||||
}
|
||||
|
||||
static PgfExpr
|
||||
pgf_cat_to_expr(PgfCCat* cat, GuChoice* choice, GuPool* pool);
|
||||
|
||||
static PgfExpr
|
||||
pgf_production_to_expr(PgfProduction prod, GuChoice* choice, GuPool* pool)
|
||||
{
|
||||
GuVariantInfo pi = gu_variant_open(prod);
|
||||
switch (pi.tag) {
|
||||
case PGF_PRODUCTION_APPLY: {
|
||||
PgfProductionApply* papp = pi.data;
|
||||
PgfExpr expr = gu_new_variant_i(pool, PGF_EXPR_FUN,
|
||||
PgfExprFun,
|
||||
.fun = papp->fun->fun);
|
||||
size_t n_args = gu_seq_length(papp->args);
|
||||
for (size_t i = 0; i < n_args; i++) {
|
||||
PgfPArg* parg = gu_seq_index(papp->args, PgfPArg, i);
|
||||
gu_assert(!parg->hypos || !parg->hypos->len);
|
||||
PgfExpr earg = pgf_cat_to_expr(parg->ccat, choice, pool);
|
||||
expr = gu_new_variant_i(pool, PGF_EXPR_APP,
|
||||
PgfExprApp,
|
||||
.fun = expr, .arg = earg);
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
case PGF_PRODUCTION_COERCE: {
|
||||
PgfProductionCoerce* pcoerce = pi.data;
|
||||
return pgf_cat_to_expr(pcoerce->coerce, choice, pool);
|
||||
}
|
||||
default:
|
||||
gu_impossible();
|
||||
}
|
||||
return gu_null_variant;
|
||||
}
|
||||
|
||||
|
||||
static PgfExpr
|
||||
pgf_cat_to_expr(PgfCCat* cat, GuChoice* choice, GuPool* pool)
|
||||
{
|
||||
if (cat->fid != PGF_FID_SYNTHETIC) {
|
||||
// XXX: What should the PgfMetaId be?
|
||||
return gu_new_variant_i(pool, PGF_EXPR_META,
|
||||
PgfExprMeta,
|
||||
.id = 0);
|
||||
}
|
||||
size_t n_prods = gu_seq_length(cat->prods);
|
||||
int i = gu_choice_next(choice, n_prods);
|
||||
if (i == -1) {
|
||||
return gu_null_variant;
|
||||
}
|
||||
PgfProduction prod = gu_seq_get(cat->prods, PgfProduction, i);
|
||||
return pgf_production_to_expr(prod, choice, pool);
|
||||
}
|
||||
|
||||
|
||||
static PgfExpr
|
||||
pgf_parse_result_next(PgfParseResult* pr, GuPool* pool)
|
||||
{
|
||||
if (pr->choice == NULL) {
|
||||
return gu_null_variant;
|
||||
}
|
||||
size_t n_results = gu_buf_length(pr->completed);
|
||||
GuChoiceMark mark = gu_choice_mark(pr->choice);
|
||||
int i = gu_choice_next(pr->choice, n_results);
|
||||
if (i == -1) {
|
||||
return gu_null_variant;
|
||||
}
|
||||
PgfCCat* cat = gu_buf_get(pr->completed, PgfCCat*, i);
|
||||
PgfExpr ret = pgf_cat_to_expr(cat, pr->choice, pool);
|
||||
gu_choice_reset(pr->choice, mark);
|
||||
if (!gu_choice_advance(pr->choice)) {
|
||||
pr->choice = NULL;
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
pgf_parse_result_enum_next(GuEnum* self, void* to, GuPool* pool)
|
||||
{
|
||||
PgfParseResult* pr = gu_container(self, PgfParseResult, en);
|
||||
*(PgfExpr*)to = pgf_parse_result_next(pr, pool);
|
||||
}
|
||||
|
||||
PgfExprEnum*
|
||||
pgf_parse_result(PgfParse* parse, GuPool* pool)
|
||||
{
|
||||
return &gu_new_i(pool, PgfParseResult,
|
||||
.completed = parse->completed,
|
||||
.choice = gu_new_choice(pool),
|
||||
.en.next = pgf_parse_result_enum_next)->en;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// TODO: s/CId/Cat, add the cid to Cat, make Cat the key to CncCat
|
||||
PgfParse*
|
||||
pgf_parser_parse(PgfParser* parser, PgfCId cat, size_t lin_idx, GuPool* pool)
|
||||
{
|
||||
PgfParse* parse = pgf_new_parse(parser, pool);
|
||||
GuPool* tmp_pool = gu_new_pool();
|
||||
PgfParsing* parsing = pgf_new_parsing(parse, pool, tmp_pool);
|
||||
PgfCncCat* cnccat =
|
||||
gu_map_get(parser->concr->cnccats, &cat, PgfCncCat*);
|
||||
if (!cnccat) {
|
||||
// error ...
|
||||
gu_impossible();
|
||||
}
|
||||
gu_assert(lin_idx < cnccat->n_lins);
|
||||
size_t n_ccats = gu_list_length(cnccat->cats);
|
||||
for (size_t i = 0; i < n_ccats; i++) {
|
||||
PgfCCat* ccat = gu_list_index(cnccat->cats, i);
|
||||
if (ccat != NULL) {
|
||||
pgf_parsing_predict(parsing, NULL, ccat, lin_idx);
|
||||
}
|
||||
}
|
||||
gu_pool_free(tmp_pool);
|
||||
return parse;
|
||||
}
|
||||
|
||||
PgfParser*
|
||||
pgf_new_parser(PgfConcr* concr, GuPool* pool)
|
||||
{
|
||||
gu_require(concr != NULL);
|
||||
PgfParser* parser = gu_new(PgfParser, pool);
|
||||
parser->concr = concr;
|
||||
return parser;
|
||||
}
|
||||
127
src/runtime/c/pgf/parser.h
Normal file
127
src/runtime/c/pgf/parser.h
Normal file
@@ -0,0 +1,127 @@
|
||||
#ifndef PGF_PARSER_H_
|
||||
#define PGF_PARSER_H_
|
||||
|
||||
#include <gu/enum.h>
|
||||
#include <pgf/data.h>
|
||||
#include <pgf/expr.h>
|
||||
|
||||
/// Parsing
|
||||
/** @file
|
||||
*
|
||||
* @todo Querying the parser for expected continuations
|
||||
*
|
||||
* @todo Literals and custom categories
|
||||
*
|
||||
* @todo HOAS, dependent types...
|
||||
*/
|
||||
|
||||
typedef struct PgfParse PgfParse;
|
||||
|
||||
/** @name Creating a new parser
|
||||
*
|
||||
* A #PgfParser object can parse sentences of a single concrete category into
|
||||
* abstract syntax trees (#PgfExpr). The parser is created with
|
||||
* #pgf_new_parser.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/// A parser for a single concrete category
|
||||
typedef struct PgfParser PgfParser;
|
||||
|
||||
|
||||
/// Create a new parser
|
||||
PgfParser*
|
||||
pgf_new_parser(PgfConcr* concr, GuPool* pool);
|
||||
/**<
|
||||
* @param concr The concrete category whose sentences are to be parsed
|
||||
*
|
||||
* @pool
|
||||
*
|
||||
* @return A newly created parser for the concrete category \p concr
|
||||
*/
|
||||
|
||||
/** @}
|
||||
*
|
||||
* @name Parsing a sentence
|
||||
*
|
||||
* The progress of parsing is controlled by the client code. Firstly, the
|
||||
* parsing of a sentence is initiated with #pgf_parser_parse. This returns an
|
||||
* initial #PgfParse object, which represents the state of the parsing. A new
|
||||
* parse state is obtained by feeding a token with #pgf_parse_token. The old
|
||||
* parse state is unaffected by this, so backtracking - and even branching -
|
||||
* can be accomplished by retaining the earlier #PgfParse objects.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/// Begin parsing
|
||||
PgfParse*
|
||||
pgf_parser_parse(PgfParser* parser, PgfCId cat, size_t lin_idx, GuPool* pool);
|
||||
/**<
|
||||
* @param parser The parser to use
|
||||
*
|
||||
* @param cat The identifier of the abstract category to parse
|
||||
*
|
||||
* @param lin_idx The index of the field of the concrete category to parse
|
||||
*
|
||||
* @pool
|
||||
*
|
||||
* @return An initial parsing state.
|
||||
*/
|
||||
|
||||
|
||||
/// Feed a token to the parser
|
||||
PgfParse*
|
||||
pgf_parse_token(PgfParse* parse, PgfToken tok, GuPool* pool);
|
||||
/**<
|
||||
* @param parse The current parse state
|
||||
*
|
||||
* @param tok The token to feed
|
||||
*
|
||||
* @pool
|
||||
*
|
||||
* @return A new parse state obtained by feeding \p tok as an input to \p
|
||||
* parse, or \c NULL if the token was unexpected.
|
||||
*
|
||||
* @note The new parse state partially depends on the old one, so it doesn't
|
||||
* make sense to use a \p pool argument with a longer lifetime than that of
|
||||
* the pool used to create \parse.
|
||||
*/
|
||||
|
||||
|
||||
/** @}
|
||||
* @name Retrieving abstract syntax trees
|
||||
*
|
||||
* After the desired tokens have been fed to the parser, the resulting parse
|
||||
* state can be queried for completed results. The #pgf_parse_result function
|
||||
* returns an enumeration (#GuEnum) of possible abstract syntax trees whose
|
||||
* linearization is the sequence of tokens fed so far.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
||||
/// An enumeration of #PgfExpr elements.
|
||||
typedef GuEnum PgfExprEnum;
|
||||
|
||||
|
||||
/// Retrieve the current parses from the parse state.
|
||||
PgfExprEnum*
|
||||
pgf_parse_result(PgfParse* parse, GuPool* pool);
|
||||
/**<
|
||||
* @param parse A parse state
|
||||
*
|
||||
* @pool
|
||||
*
|
||||
* @return An enumeration of #PgfExpr elements representing the abstract
|
||||
* syntax trees that would linearize to the sequence of tokens fed to produce
|
||||
* \p parse. The enumeration may yield zero, one or more abstract syntax
|
||||
* trees, depending on whether the parse was unsuccesful, unambiguously
|
||||
* succesful, or ambiguously successful.
|
||||
*/
|
||||
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif // PGF_PARSER_H_
|
||||
78
src/runtime/c/pgf/pgf.h
Normal file
78
src/runtime/c/pgf/pgf.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2010 University of Helsinki.
|
||||
*
|
||||
* This file is part of libpgf.
|
||||
*
|
||||
* Libpgf is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Libpgf 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 Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with libpgf. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file
|
||||
*
|
||||
* The public libpgf API.
|
||||
*/
|
||||
|
||||
#ifndef PGF_H_
|
||||
#define PGF_H_
|
||||
|
||||
#include <gu/exn.h>
|
||||
#include <gu/mem.h>
|
||||
#include <gu/in.h>
|
||||
#include <gu/string.h>
|
||||
|
||||
|
||||
typedef GuString PgfCId;
|
||||
extern GU_DECLARE_TYPE(PgfCId, typedef);
|
||||
|
||||
|
||||
/// A single lexical token
|
||||
typedef GuString PgfToken;
|
||||
|
||||
/// @name PGF Grammar objects
|
||||
/// @{
|
||||
|
||||
typedef struct PgfPGF PgfPGF;
|
||||
|
||||
/**< A representation of a PGF grammar.
|
||||
*/
|
||||
|
||||
|
||||
PgfPGF*
|
||||
pgf_read(GuIn* in, GuPool* pool, GuExn* err);
|
||||
|
||||
/**< Read a grammar from a PGF file.
|
||||
*
|
||||
* @param from PGF input stream.
|
||||
* The stream must be positioned in the beginning of a binary
|
||||
* PGF representation. After a succesful invocation, the stream is
|
||||
* still open and positioned at the end of the representation.
|
||||
*
|
||||
* @param[out] err_out Raised error.
|
||||
* If non-\c NULL, \c *err_out should be \c NULL. Then, upon
|
||||
* failure, \c *err_out is set to point to a newly allocated
|
||||
* error object, which the caller must free with #g_exn_free
|
||||
* or #g_exn_propagate.
|
||||
*
|
||||
* @return A new PGF object, or \c NULL upon failure. The returned
|
||||
* object must later be freed with #pgf_free.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <gu/type.h>
|
||||
GU_DECLARE_TYPE(PgfPGF, struct);
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
#endif // PGF_H_
|
||||
843
src/runtime/c/pgf/reader.c
Normal file
843
src/runtime/c/pgf/reader.c
Normal file
@@ -0,0 +1,843 @@
|
||||
/*
|
||||
* Copyright 2010 University of Helsinki.
|
||||
*
|
||||
* This file is part of libpgf.
|
||||
*
|
||||
* Libpgf is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Libpgf 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 Lesser General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with libpgf. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "data.h"
|
||||
#include "expr.h"
|
||||
#include <gu/defs.h>
|
||||
#include <gu/map.h>
|
||||
#include <gu/seq.h>
|
||||
#include <gu/assert.h>
|
||||
#include <gu/intern.h>
|
||||
#include <gu/in.h>
|
||||
#include <gu/bits.h>
|
||||
#include <gu/exn.h>
|
||||
#include <gu/utf8.h>
|
||||
|
||||
#define GU_LOG_ENABLE
|
||||
#include <gu/log.h>
|
||||
|
||||
typedef struct PgfIdContext PgfIdContext;
|
||||
|
||||
//
|
||||
// PgfReader
|
||||
//
|
||||
|
||||
typedef struct PgfReader PgfReader;
|
||||
|
||||
struct PgfReader {
|
||||
GuIn* in;
|
||||
GuExn* err;
|
||||
GuPool* opool;
|
||||
GuPool* pool;
|
||||
GuSymTable* symtab;
|
||||
PgfSequences* curr_sequences;
|
||||
PgfCncFuns* curr_cncfuns;
|
||||
GuMap* curr_ccats;
|
||||
GuMap* ccat_locs;
|
||||
GuMap* curr_lindefs;
|
||||
GuMap* curr_coercions;
|
||||
GuTypeMap* read_to_map;
|
||||
GuTypeMap* read_new_map;
|
||||
void* curr_key;
|
||||
GuPool* curr_pool;
|
||||
};
|
||||
|
||||
typedef struct PgfReadTagExn PgfReadTagExn;
|
||||
|
||||
struct PgfReadTagExn {
|
||||
GuType* type;
|
||||
int tag;
|
||||
};
|
||||
|
||||
static GU_DEFINE_TYPE(PgfReadTagExn, abstract, _);
|
||||
|
||||
static GU_DEFINE_TYPE(PgfReadExn, abstract, _);
|
||||
|
||||
static uint8_t
|
||||
pgf_read_u8(PgfReader* rdr)
|
||||
{
|
||||
uint8_t u = gu_in_u8(rdr->in, rdr->err);
|
||||
gu_debug("u8: %u", u);
|
||||
return u;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
pgf_read_uint(PgfReader* rdr)
|
||||
{
|
||||
uint32_t u = 0;
|
||||
int shift = 0;
|
||||
uint8_t b = 0;
|
||||
do {
|
||||
b = pgf_read_u8(rdr);
|
||||
gu_return_on_exn(rdr->err, 0);
|
||||
u |= (b & ~0x80) << shift;
|
||||
shift += 7;
|
||||
} while (b & 0x80);
|
||||
gu_debug("uint: %u", u);
|
||||
return u;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
pgf_read_int(PgfReader* rdr)
|
||||
{
|
||||
uint32_t u = pgf_read_uint(rdr);
|
||||
return gu_decode_2c32(u, rdr->err);
|
||||
}
|
||||
|
||||
static GuLength
|
||||
pgf_read_len(PgfReader* rdr)
|
||||
{
|
||||
int32_t len = pgf_read_int(rdr);
|
||||
// It's crucial that we return 0 on failure, so the
|
||||
// caller can proceed without checking for error
|
||||
// immediately.
|
||||
gu_return_on_exn(rdr->err, 0);
|
||||
if (len < 0) {
|
||||
gu_raise_i(rdr->err, PgfReadTagExn,
|
||||
.type = gu_type(GuLength), .tag = len);
|
||||
return 0;
|
||||
}
|
||||
return (GuLength) len;
|
||||
}
|
||||
|
||||
typedef const struct PgfReadToFn PgfReadToFn;
|
||||
|
||||
struct PgfReadToFn {
|
||||
void (*fn)(GuType* type, PgfReader* rdr, void* to);
|
||||
};
|
||||
|
||||
static void
|
||||
pgf_read_to(PgfReader* rdr, GuType* type, void* to) {
|
||||
PgfReadToFn* fn = gu_type_map_get(rdr->read_to_map, type);
|
||||
fn->fn(type, rdr, to);
|
||||
}
|
||||
|
||||
typedef const struct PgfReadNewFn PgfReadNewFn;
|
||||
struct PgfReadNewFn {
|
||||
void* (*fn)(GuType* type, PgfReader* rdr, GuPool* pool,
|
||||
size_t* size_out);
|
||||
};
|
||||
|
||||
static void*
|
||||
pgf_read_new(PgfReader* rdr, GuType* type, GuPool* pool, size_t* size_out)
|
||||
{
|
||||
size_t size = 0;
|
||||
PgfReadNewFn* fn = gu_type_map_get(rdr->read_new_map, type);
|
||||
return fn->fn(type, rdr, pool, size_out ? size_out : &size);
|
||||
}
|
||||
|
||||
static void*
|
||||
pgf_read_new_type(GuType* type, PgfReader* rdr, GuPool* pool,
|
||||
size_t* size_out)
|
||||
{
|
||||
GuTypeRepr* repr = gu_type_repr(type);
|
||||
void* to = gu_malloc_aligned(pool, repr->size, repr->align);
|
||||
pgf_read_to(rdr, type, to);
|
||||
*size_out = repr->size;
|
||||
return to;
|
||||
}
|
||||
|
||||
static void*
|
||||
pgf_read_struct(GuStructRepr* stype, PgfReader* rdr, void* to,
|
||||
GuPool* pool, size_t* size_out)
|
||||
{
|
||||
GuTypeRepr* repr = gu_type_cast((GuType*)stype, repr);
|
||||
size_t size = repr->size;
|
||||
GuLength length = 0;
|
||||
bool have_length = false;
|
||||
uint8_t* p = NULL;
|
||||
uint8_t* bto = to;
|
||||
gu_enter("-> struct %s", stype->name);
|
||||
|
||||
for (int i = 0; i < stype->members.len; i++) {
|
||||
const GuMember* m = &stype->members.elems[i];
|
||||
gu_enter("-> %s.%s", stype->name, m->name);
|
||||
if (m->is_flex) {
|
||||
gu_assert(have_length && p == NULL && pool != NULL);
|
||||
size_t m_size = gu_type_size(m->type);
|
||||
size = gu_flex_size(size, m->offset,
|
||||
length, m_size);
|
||||
p = gu_malloc_aligned(pool, size, repr->align);
|
||||
for (size_t j = 0; j < length; j++) {
|
||||
pgf_read_to(rdr, m->type,
|
||||
&p[m->offset + j * m_size]);
|
||||
gu_return_on_exn(rdr->err, NULL);
|
||||
}
|
||||
} else {
|
||||
pgf_read_to(rdr, m->type, &bto[m->offset]);
|
||||
gu_return_on_exn(rdr->err, NULL);
|
||||
}
|
||||
if (m->type == gu_type(GuLength)) {
|
||||
gu_assert(!have_length);
|
||||
have_length = true;
|
||||
length = gu_member(GuLength, to, m->offset);
|
||||
}
|
||||
gu_exit("<- %s.%s", stype->name, m->name);
|
||||
}
|
||||
if (p) {
|
||||
memcpy(p, to, repr->size);
|
||||
}
|
||||
if (size_out) {
|
||||
*size_out = size;
|
||||
}
|
||||
gu_exit("<- struct %s", stype->name);
|
||||
return p;
|
||||
}
|
||||
|
||||
static void
|
||||
pgf_read_to_struct(GuType* type, PgfReader* rdr, void* to)
|
||||
{
|
||||
GuStructRepr* stype = gu_type_cast(type, struct);
|
||||
pgf_read_struct(stype, rdr, to, NULL, NULL);
|
||||
}
|
||||
|
||||
static void*
|
||||
pgf_read_new_struct(GuType* type, PgfReader* rdr,
|
||||
GuPool* pool, size_t* size_out)
|
||||
{
|
||||
GuStructRepr* stype = gu_type_cast(type, struct);
|
||||
if (gu_struct_has_flex(stype)) {
|
||||
GuPool* tmp_pool = gu_new_pool();
|
||||
void* to = gu_type_malloc(type, tmp_pool);
|
||||
void* p = pgf_read_struct(stype, rdr, to, pool, size_out);
|
||||
gu_pool_free(tmp_pool);
|
||||
gu_assert(p);
|
||||
return p;
|
||||
} else {
|
||||
void* to = gu_type_malloc(type, pool);
|
||||
pgf_read_struct(stype, rdr, to, NULL, NULL);
|
||||
return to;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
pgf_read_to_pointer(GuType* type, PgfReader* rdr, void* to)
|
||||
{
|
||||
GuPointerType* ptype = (GuPointerType*) type;
|
||||
GuType* pointed = ptype->pointed_type;
|
||||
gu_require(gu_type_has_kind(pointed, gu_kind(struct)) ||
|
||||
gu_type_has_kind(pointed, gu_kind(abstract)));
|
||||
GuStruct** sto = to;
|
||||
*sto = pgf_read_new(rdr, pointed, rdr->opool, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
pgf_read_to_GuVariant(GuType* type, PgfReader* rdr, void* to)
|
||||
{
|
||||
GuVariantType* vtype = (GuVariantType*) type;
|
||||
GuVariant* vto = to;
|
||||
|
||||
uint8_t btag = pgf_read_u8(rdr);
|
||||
gu_return_on_exn(rdr->err,);
|
||||
if (btag >= vtype->ctors.len) {
|
||||
gu_raise_i(rdr->err, PgfReadTagExn,
|
||||
.type = type, .tag = btag);
|
||||
return;
|
||||
}
|
||||
GuConstructor* ctor = &vtype->ctors.elems[btag];
|
||||
gu_enter("-> variant %s", ctor->c_name);
|
||||
GuPool* tmp_pool = gu_new_pool();
|
||||
GuTypeRepr* repr = gu_type_repr(ctor->type);
|
||||
size_t size = repr->size;
|
||||
void* init = pgf_read_new(rdr, ctor->type, tmp_pool, &size);
|
||||
*vto = gu_make_variant(btag, size, repr->align, init, rdr->opool);
|
||||
gu_pool_free(tmp_pool);
|
||||
gu_exit("<- variant %s", ctor->c_name);
|
||||
}
|
||||
|
||||
static void
|
||||
pgf_read_to_enum(GuType* type, PgfReader* rdr, void* to)
|
||||
{
|
||||
// For now, assume that enum values are encoded in a single octet
|
||||
GuEnumType* etype = (GuEnumType*) type;
|
||||
uint8_t tag = pgf_read_u8(rdr);
|
||||
gu_return_on_exn(rdr->err,);
|
||||
if (tag >= etype->constants.len) {
|
||||
gu_raise_i(rdr->err, PgfReadTagExn,
|
||||
.type = type, .tag = tag);
|
||||
return;
|
||||
}
|
||||
GuEnumConstant* econ = &etype->constants.elems[tag];
|
||||
size_t size = gu_type_size(type);
|
||||
if (size == sizeof(int8_t)) {
|
||||
*((int8_t*) to) = econ->value;
|
||||
} else if (size == sizeof(int16_t)) {
|
||||
*((int16_t*) to) = econ->value;
|
||||
} else if (size == sizeof(int32_t)) {
|
||||
*((int32_t*) to) = econ->value;
|
||||
} else if (size == sizeof(int64_t)) {
|
||||
*((int64_t*) to) = econ->value;
|
||||
} else {
|
||||
gu_impossible();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pgf_read_to_void(GuType* info, PgfReader* rdr, void* to)
|
||||
{
|
||||
(void) (info && rdr && to);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
pgf_read_to_int(GuType* type, PgfReader* rdr, void* to)
|
||||
{
|
||||
(void) type;
|
||||
*(int*) to = pgf_read_int(rdr);
|
||||
}
|
||||
|
||||
static void
|
||||
pgf_read_to_uint16_t(GuType* type, PgfReader* rdr, void* to)
|
||||
{
|
||||
(void) type;
|
||||
*(uint16_t*) to = gu_in_u16be(rdr->in, rdr->err);
|
||||
}
|
||||
|
||||
static void
|
||||
pgf_read_to_GuLength(GuType* type, PgfReader* rdr, void* to)
|
||||
{
|
||||
(void) type;
|
||||
*(GuLength*) to = pgf_read_len(rdr);
|
||||
}
|
||||
|
||||
static void
|
||||
pgf_read_to_double(GuType* type, PgfReader* rdr, void* to)
|
||||
{
|
||||
(void) type;
|
||||
*(double*) to = gu_in_f64be(rdr->in, rdr->err);
|
||||
}
|
||||
|
||||
static void
|
||||
pgf_read_to_alias(GuType* type, PgfReader* rdr, void* to)
|
||||
{
|
||||
GuTypeAlias* atype = gu_type_cast(type, alias);
|
||||
pgf_read_to(rdr, atype->type, to);
|
||||
}
|
||||
|
||||
static void
|
||||
pgf_read_into_map(GuMapType* mtype, PgfReader* rdr, GuMap* map, GuPool* pool)
|
||||
{
|
||||
/* The parameter pool is the temporary pool used to store the
|
||||
map. But the actual values need to be more persistent so we
|
||||
store them in rdr->opool. */
|
||||
(void) pool;
|
||||
GuPool* tmp_pool = gu_new_pool();
|
||||
void* key = NULL;
|
||||
GuLength len = pgf_read_len(rdr);
|
||||
gu_return_on_exn(rdr->err, );
|
||||
if (mtype->hasher) {
|
||||
key = gu_type_malloc(mtype->key_type, tmp_pool);
|
||||
}
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
if (mtype->hasher) {
|
||||
pgf_read_to(rdr, mtype->key_type, key);
|
||||
} else {
|
||||
key = pgf_read_new(rdr, mtype->key_type,
|
||||
rdr->opool, NULL);
|
||||
}
|
||||
gu_return_on_exn(rdr->err, );
|
||||
rdr->curr_key = key;
|
||||
/* If an old value already exists, read into
|
||||
it. This allows us to create the value
|
||||
object and point into it before we read the
|
||||
content. */
|
||||
void* valp = gu_map_insert(map, key);
|
||||
pgf_read_to(rdr, mtype->value_type, valp);
|
||||
gu_return_on_exn(rdr->err, );
|
||||
}
|
||||
gu_pool_free(tmp_pool);
|
||||
}
|
||||
|
||||
static void*
|
||||
pgf_read_new_GuMap(GuType* type, PgfReader* rdr, GuPool* pool, size_t* size_out)
|
||||
{
|
||||
(void) size_out;
|
||||
GuMapType* mtype = (GuMapType*) type;
|
||||
GuMap* map = gu_map_type_make(mtype, pool);
|
||||
pgf_read_into_map(mtype, rdr, map, pool);
|
||||
gu_return_on_exn(rdr->err, NULL);
|
||||
return map;
|
||||
}
|
||||
|
||||
static void
|
||||
pgf_read_to_GuString(GuType* type, PgfReader* rdr, void* to)
|
||||
{
|
||||
(void) (type);
|
||||
gu_enter("-> GuString");
|
||||
GuString* sp = to;
|
||||
|
||||
GuPool* tmp_pool = gu_new_pool();
|
||||
GuStringBuf* sbuf = gu_string_buf(tmp_pool);
|
||||
GuWriter* wtr = gu_string_buf_writer(sbuf);
|
||||
|
||||
GuLength len = pgf_read_len(rdr);
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
GuUCS ucs = gu_in_utf8(rdr->in, rdr->err);
|
||||
gu_ucs_write(ucs, wtr, rdr->err);
|
||||
}
|
||||
GuString str = gu_string_buf_freeze(sbuf, tmp_pool);
|
||||
GuSymbol sym = gu_symtable_intern(rdr->symtab, str);
|
||||
gu_pool_free(tmp_pool);
|
||||
|
||||
gu_exit("<- GuString");
|
||||
*sp = sym;
|
||||
}
|
||||
|
||||
static void
|
||||
pgf_read_to_PgfCId(GuType* type, PgfReader* rdr, void* to)
|
||||
{
|
||||
(void) (type);
|
||||
gu_enter("-> PgfCId");
|
||||
PgfCId* sp = to;
|
||||
|
||||
GuPool* tmp_pool = gu_new_pool();
|
||||
GuStringBuf* sbuf = gu_string_buf(tmp_pool);
|
||||
GuWriter* wtr = gu_string_buf_writer(sbuf);
|
||||
|
||||
GuLength len = pgf_read_len(rdr);
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
// CIds are in latin-1
|
||||
GuUCS ucs = gu_in_u8(rdr->in, rdr->err);
|
||||
gu_ucs_write(ucs, wtr, rdr->err);
|
||||
}
|
||||
GuString str = gu_string_buf_freeze(sbuf, tmp_pool);
|
||||
GuSymbol sym = gu_symtable_intern(rdr->symtab, str);
|
||||
gu_pool_free(tmp_pool);
|
||||
|
||||
gu_exit("<- PgfCId");
|
||||
*sp = sym;
|
||||
}
|
||||
|
||||
static void
|
||||
pgf_read_to_PgfCCatId(GuType* type, PgfReader* rdr, void* to)
|
||||
{
|
||||
(void) (type);
|
||||
PgfCCat** pto = to;
|
||||
int fid = pgf_read_int(rdr);
|
||||
gu_return_on_exn(rdr->err,);
|
||||
PgfCCat* ccat = gu_map_get(rdr->curr_ccats, &fid, PgfCCat*);
|
||||
if (ccat) {
|
||||
*pto = ccat;
|
||||
return;
|
||||
}
|
||||
GuBuf* locs = gu_map_get(rdr->ccat_locs, &fid, GuBuf*);
|
||||
if (!locs) {
|
||||
locs = gu_new_buf(PgfCCat**, rdr->pool);
|
||||
gu_map_put(rdr->ccat_locs, &fid, GuBuf*, locs);
|
||||
}
|
||||
gu_buf_push(locs, PgfCCat**, pto);
|
||||
}
|
||||
|
||||
static void
|
||||
pgf_read_to_PgfCCat(GuType* type, PgfReader* rdr, void* to)
|
||||
{
|
||||
(void) type;
|
||||
gu_enter("->");
|
||||
PgfCCat* cat = to;
|
||||
cat->cnccat = NULL;
|
||||
pgf_read_to(rdr, gu_type(PgfProductionSeq), &cat->prods);
|
||||
int* fidp = rdr->curr_key;
|
||||
cat->fid = *fidp;
|
||||
GuBuf* locs_buf = gu_map_get(rdr->ccat_locs, fidp, GuBuf*);
|
||||
if (locs_buf) {
|
||||
size_t len = gu_buf_length(locs_buf);
|
||||
PgfCCat*** locs = gu_buf_data(locs_buf);
|
||||
for (size_t n = 0; n < len; n++) {
|
||||
*(locs[n]) = cat;
|
||||
}
|
||||
}
|
||||
gu_exit("<-");
|
||||
}
|
||||
|
||||
// This is only needed because new_struct would otherwise override.
|
||||
// TODO: get rid of new_struct and all the FAM mess
|
||||
static void*
|
||||
pgf_read_new_PgfCCat(GuType* type, PgfReader* rdr, GuPool* pool,
|
||||
size_t* size_out)
|
||||
{
|
||||
PgfCCat* ccat = gu_new(PgfCCat, pool);
|
||||
pgf_read_to_PgfCCat(type, rdr, ccat);
|
||||
*size_out = sizeof(PgfCCat);
|
||||
return ccat;
|
||||
}
|
||||
|
||||
static void*
|
||||
pgf_read_new_GuList(GuType* type, PgfReader* rdr, GuPool* pool, size_t* size_out)
|
||||
{
|
||||
GuListType* ltype = gu_type_cast(type, GuList);
|
||||
GuLength length = pgf_read_len(rdr);
|
||||
gu_return_on_exn(rdr->err, NULL);
|
||||
void* list = gu_list_type_alloc(ltype, length, pool);
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
void* elem = gu_list_type_index(ltype, list, i);
|
||||
pgf_read_to(rdr, ltype->elem_type, elem);
|
||||
gu_return_on_exn(rdr->err, NULL);
|
||||
}
|
||||
*size_out = gu_flex_size(ltype->size, ltype->elems_offset,
|
||||
length,
|
||||
gu_type_size(ltype->elem_type));
|
||||
return list;
|
||||
}
|
||||
|
||||
static void
|
||||
pgf_read_to_GuSeq(GuType* type, PgfReader* rdr, void* to)
|
||||
{
|
||||
gu_enter("->");
|
||||
GuSeqType* stype = gu_type_cast(type, GuSeq);
|
||||
GuLength length = pgf_read_len(rdr);
|
||||
GuTypeRepr* repr = gu_type_repr(stype->elem_type);
|
||||
gu_return_on_exn(rdr->err, );
|
||||
GuSeq seq = gu_make_seq(repr->size, length, rdr->opool);
|
||||
uint8_t* data = gu_seq_data(seq);
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
void* elem = &data[i * repr->size];
|
||||
pgf_read_to(rdr, stype->elem_type, elem);
|
||||
gu_return_on_exn(rdr->err, );
|
||||
}
|
||||
GuSeq* sto = to;
|
||||
*sto = seq;
|
||||
gu_exit("<-");
|
||||
}
|
||||
|
||||
static void
|
||||
pgf_read_to_maybe_seq(GuType* type, PgfReader* rdr, void* to)
|
||||
{
|
||||
GuSeq* sto = to;
|
||||
uint8_t tag = pgf_read_u8(rdr);
|
||||
gu_return_on_exn(rdr->err,);
|
||||
switch (tag) {
|
||||
case 0:
|
||||
*sto = gu_null_seq;
|
||||
break;
|
||||
case 1:
|
||||
pgf_read_to_GuSeq(type, rdr, to);
|
||||
break;
|
||||
default:
|
||||
gu_raise_i(rdr->err, PgfReadTagExn,
|
||||
.type = type, .tag = tag);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void*
|
||||
pgf_read_new_idarray(GuType* type, PgfReader* rdr, GuPool* pool,
|
||||
size_t* size_out)
|
||||
{
|
||||
(void) type;
|
||||
void* list = pgf_read_new_GuList(type, rdr, rdr->curr_pool, size_out);
|
||||
if (type == gu_type(PgfSequences)) {
|
||||
rdr->curr_sequences = list;
|
||||
} else if (type == gu_type(PgfCncFuns)) {
|
||||
rdr->curr_cncfuns = list;
|
||||
} else {
|
||||
gu_impossible();
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
static void
|
||||
pgf_read_to_PgfSeqId(GuType* type, PgfReader* rdr, void* to)
|
||||
{
|
||||
(void) type;
|
||||
int32_t id = pgf_read_int(rdr);
|
||||
gu_return_on_exn(rdr->err,);
|
||||
if (id < 0 || id >= gu_list_length(rdr->curr_sequences)) {
|
||||
gu_raise(rdr->err, PgfReadExn);
|
||||
return;
|
||||
}
|
||||
*(PgfSeqId*) to = gu_list_elems(rdr->curr_sequences)[id];
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
pgf_read_to_PgfFunId(GuType* type, PgfReader* rdr, void* to)
|
||||
{
|
||||
(void) type;
|
||||
int32_t id = pgf_read_int(rdr);
|
||||
gu_return_on_exn(rdr->err,);
|
||||
if (id < 0 || id >= gu_list_length(rdr->curr_cncfuns)) {
|
||||
gu_raise(rdr->err, PgfReadExn);
|
||||
return;
|
||||
}
|
||||
*(PgfFunId*) to = gu_list_elems(rdr->curr_cncfuns)[id];
|
||||
}
|
||||
|
||||
static GU_DEFINE_TYPE(PgfLinDefs, GuIntMap, gu_ptr_type(PgfFunIds),
|
||||
&gu_null_struct);
|
||||
typedef PgfCCat PgfCCatData;
|
||||
static GU_DEFINE_TYPE(PgfCCatData, typedef, gu_type(PgfCCat));
|
||||
|
||||
static GU_DEFINE_TYPE(PgfCCatMap, GuIntMap, gu_ptr_type(PgfCCat),
|
||||
&gu_null_struct);
|
||||
|
||||
static GU_DEFINE_TYPE(PgfCncCatMap, GuStringMap, gu_ptr_type(PgfCncCat),
|
||||
&gu_null_struct);
|
||||
|
||||
typedef struct {
|
||||
GuMapItor fn;
|
||||
GuBuf* seq;
|
||||
} PgfCCatCbCtx;
|
||||
|
||||
static PgfCncCat*
|
||||
pgf_ccat_set_cnccat(PgfCCat* ccat, GuBuf* newly_set)
|
||||
{
|
||||
if (!ccat->cnccat) {
|
||||
size_t n_prods = gu_seq_length(ccat->prods);
|
||||
for (size_t i = 0; i < n_prods; i++) {
|
||||
PgfProduction prod =
|
||||
gu_seq_get(ccat->prods, PgfProduction, i);
|
||||
GuVariantInfo i = gu_variant_open(prod);
|
||||
switch (i.tag) {
|
||||
case PGF_PRODUCTION_COERCE: {
|
||||
PgfProductionCoerce* pcoerce = i.data;
|
||||
PgfCncCat* cnccat =
|
||||
pgf_ccat_set_cnccat(pcoerce->coerce,
|
||||
newly_set);
|
||||
if (!ccat->cnccat) {
|
||||
ccat->cnccat = cnccat;
|
||||
} else if (ccat->cnccat != cnccat) {
|
||||
// XXX: real error
|
||||
gu_impossible();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PGF_PRODUCTION_APPLY:
|
||||
// Shouldn't happen with current PGF.
|
||||
// XXX: real error
|
||||
gu_impossible();
|
||||
break;
|
||||
default:
|
||||
gu_impossible();
|
||||
}
|
||||
}
|
||||
gu_buf_push(newly_set, PgfCCat*, ccat);
|
||||
}
|
||||
return ccat->cnccat;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
pgf_read_ccat_cb(GuMapItor* fn, const void* key, void* value, GuExn* err)
|
||||
{
|
||||
(void) (key && err);
|
||||
PgfCCatCbCtx* ctx = (PgfCCatCbCtx*) fn;
|
||||
PgfCCat** ccatp = value;
|
||||
pgf_ccat_set_cnccat(*ccatp, ctx->seq);
|
||||
}
|
||||
|
||||
static void*
|
||||
pgf_read_new_PgfConcr(GuType* type, PgfReader* rdr, GuPool* pool,
|
||||
size_t* size_out)
|
||||
{
|
||||
(void) (type && size_out);
|
||||
/* We allocate indices from a temporary pool. The actual data
|
||||
* is allocated from rdr->opool. Once everything is resolved
|
||||
* and indices aren't needed, the temporary pool can be
|
||||
* freed. */
|
||||
GuPool* tmp_pool = gu_new_pool();
|
||||
rdr->curr_pool = tmp_pool;
|
||||
PgfConcr* concr = gu_new(PgfConcr, pool);;
|
||||
concr->cflags =
|
||||
pgf_read_new(rdr, gu_type(PgfFlags), pool, NULL);
|
||||
concr->printnames =
|
||||
pgf_read_new(rdr, gu_type(PgfPrintNames), pool, NULL);
|
||||
rdr->curr_sequences =
|
||||
pgf_read_new(rdr, gu_type(PgfSequences), pool, NULL);
|
||||
rdr->curr_cncfuns =
|
||||
pgf_read_new(rdr, gu_type(PgfCncFuns), pool, NULL);
|
||||
GuMapType* lindefs_t = gu_type_cast(gu_type(PgfLinDefs), GuMap);
|
||||
rdr->curr_lindefs = gu_map_type_make(lindefs_t, tmp_pool);
|
||||
pgf_read_into_map(lindefs_t, rdr, rdr->curr_lindefs, rdr->opool);
|
||||
GuMapType* ccats_t = gu_type_cast(gu_type(PgfCCatMap), GuMap);
|
||||
rdr->curr_ccats =
|
||||
gu_new_int_map(PgfCCat*, &gu_null_struct, tmp_pool);
|
||||
rdr->ccat_locs =
|
||||
gu_new_int_map(GuBuf*, &gu_null_struct, tmp_pool);
|
||||
pgf_read_into_map(ccats_t, rdr, rdr->curr_ccats, rdr->opool);
|
||||
concr->cnccats = pgf_read_new(rdr, gu_type(PgfCncCatMap),
|
||||
rdr->opool, NULL);
|
||||
|
||||
GuBuf* extra_ccats = gu_new_buf(PgfCCat*, tmp_pool);
|
||||
PgfCCatCbCtx ctx = { { pgf_read_ccat_cb }, extra_ccats };
|
||||
gu_map_iter(rdr->curr_ccats, &ctx.fn, NULL);
|
||||
concr->extra_ccats = gu_buf_freeze(extra_ccats, rdr->opool);
|
||||
(void) pgf_read_int(rdr); // totalcats
|
||||
gu_pool_free(tmp_pool);
|
||||
return concr;
|
||||
}
|
||||
|
||||
static bool
|
||||
pgf_ccat_n_lins(PgfCCat* cat, int* n_lins) {
|
||||
if (gu_seq_is_null(cat->prods)) {
|
||||
return true;
|
||||
}
|
||||
size_t n_prods = gu_seq_length(cat->prods);
|
||||
for (size_t j = 0; j < n_prods; j++) {
|
||||
PgfProduction prod =
|
||||
gu_seq_get(cat->prods, PgfProduction, j);
|
||||
GuVariantInfo i = gu_variant_open(prod);
|
||||
switch (i.tag) {
|
||||
case PGF_PRODUCTION_APPLY: {
|
||||
PgfProductionApply* papp = i.data;
|
||||
if (*n_lins == -1) {
|
||||
*n_lins = (int) papp->fun->n_lins;
|
||||
} else if (*n_lins != (int) papp->fun->n_lins) {
|
||||
// Inconsistent n_lins for different productions!
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PGF_PRODUCTION_COERCE: {
|
||||
PgfProductionCoerce* pcoerce = i.data;
|
||||
bool succ = pgf_ccat_n_lins(pcoerce->coerce, n_lins);
|
||||
if (!succ) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
gu_impossible();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void*
|
||||
pgf_read_new_PgfCncCat(GuType* type, PgfReader* rdr, GuPool* pool,
|
||||
size_t* size_out)
|
||||
{
|
||||
PgfCId cid = *(PgfCId*) rdr->curr_key;
|
||||
gu_enter("-> cid");
|
||||
(void) (type && size_out);
|
||||
PgfCncCat* cnccat = gu_new(PgfCncCat, pool);
|
||||
cnccat->cid = cid;
|
||||
int first = pgf_read_int(rdr);
|
||||
int last = pgf_read_int(rdr);
|
||||
int len = last + 1 - first;
|
||||
PgfCCatIds* cats = gu_new_list(PgfCCatIds, pool, len);
|
||||
int n_lins = -1;
|
||||
for (int i = 0; i < len; i++) {
|
||||
int n = first + i;
|
||||
PgfCCat* ccat = gu_map_get(rdr->curr_ccats, &n, PgfCCat*);
|
||||
/* ccat can be NULL if the PGF is optimized and the
|
||||
* category has been erased as useless */
|
||||
gu_list_index(cats, i) = ccat;
|
||||
if (ccat != NULL) {
|
||||
// TODO: error if overlap
|
||||
ccat->cnccat = cnccat;
|
||||
if (!pgf_ccat_n_lins(ccat, &n_lins)) {
|
||||
gu_raise(rdr->err, PgfReadExn);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
}
|
||||
gu_debug("range[%d] = %d", i, ccat ? ccat->fid : -1);
|
||||
}
|
||||
cnccat->n_lins = n_lins == -1 ? 0 : (size_t) n_lins;
|
||||
cnccat->cats = cats;
|
||||
cnccat->lindefs = gu_map_get(rdr->curr_lindefs, &first, PgfFunIds*);
|
||||
cnccat->labels = pgf_read_new(rdr, gu_type(GuStringL),
|
||||
pool, NULL);
|
||||
gu_exit("<-");
|
||||
return cnccat;
|
||||
fail:
|
||||
gu_exit("<- fail");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define PGF_READ_TO_FN(k_, fn_) \
|
||||
{ gu_kind(k_), (void*) &(PgfReadToFn){ fn_ } }
|
||||
|
||||
#define PGF_READ_TO(k_) \
|
||||
PGF_READ_TO_FN(k_, pgf_read_to_##k_)
|
||||
|
||||
|
||||
static GuTypeTable
|
||||
pgf_read_to_table = GU_TYPETABLE(
|
||||
GU_SLIST_0,
|
||||
PGF_READ_TO(struct),
|
||||
PGF_READ_TO(GuVariant),
|
||||
PGF_READ_TO(enum),
|
||||
PGF_READ_TO(void),
|
||||
PGF_READ_TO(int),
|
||||
PGF_READ_TO(uint16_t),
|
||||
PGF_READ_TO(GuLength),
|
||||
PGF_READ_TO(PgfCId),
|
||||
PGF_READ_TO(GuString),
|
||||
PGF_READ_TO(double),
|
||||
PGF_READ_TO(pointer),
|
||||
PGF_READ_TO_FN(PgfEquationsM, pgf_read_to_maybe_seq),
|
||||
PGF_READ_TO(GuSeq),
|
||||
PGF_READ_TO(PgfCCatId),
|
||||
PGF_READ_TO(PgfCCat),
|
||||
PGF_READ_TO(PgfSeqId),
|
||||
PGF_READ_TO(PgfFunId),
|
||||
PGF_READ_TO(alias));
|
||||
|
||||
#define PGF_READ_NEW_FN(k_, fn_) \
|
||||
{ gu_kind(k_), (void*) &(PgfReadNewFn){ fn_ } }
|
||||
|
||||
#define PGF_READ_NEW(k_) \
|
||||
PGF_READ_NEW_FN(k_, pgf_read_new_##k_)
|
||||
|
||||
static GuTypeTable
|
||||
pgf_read_new_table = GU_TYPETABLE(
|
||||
GU_SLIST_0,
|
||||
PGF_READ_NEW(type),
|
||||
PGF_READ_NEW(struct),
|
||||
PGF_READ_NEW(GuMap),
|
||||
PGF_READ_NEW(GuList),
|
||||
PGF_READ_NEW(PgfCCat),
|
||||
PGF_READ_NEW(PgfCncCat),
|
||||
PGF_READ_NEW(PgfConcr),
|
||||
PGF_READ_NEW_FN(PgfSequences, pgf_read_new_idarray),
|
||||
PGF_READ_NEW_FN(PgfCncFuns, pgf_read_new_idarray)
|
||||
);
|
||||
|
||||
static PgfReader*
|
||||
pgf_new_reader(GuIn* in, GuPool* opool, GuPool* pool, GuExn* err)
|
||||
{
|
||||
PgfReader* rdr = gu_new(PgfReader, pool);
|
||||
rdr->opool = opool;
|
||||
rdr->symtab = gu_new_symtable(opool, pool);
|
||||
rdr->err = err;
|
||||
rdr->in = in;
|
||||
rdr->curr_sequences = NULL;
|
||||
rdr->curr_cncfuns = NULL;
|
||||
rdr->read_to_map = gu_new_type_map(&pgf_read_to_table, pool);
|
||||
rdr->read_new_map = gu_new_type_map(&pgf_read_new_table, pool);
|
||||
rdr->pool = pool;
|
||||
return rdr;
|
||||
}
|
||||
|
||||
|
||||
PgfPGF*
|
||||
pgf_read(GuIn* in, GuPool* pool, GuExn* err)
|
||||
{
|
||||
GuPool* tmp_pool = gu_new_pool();
|
||||
PgfReader* rdr = pgf_new_reader(in, pool, tmp_pool, err);
|
||||
PgfPGF* pgf = pgf_read_new(rdr, gu_type(PgfPGF), pool, NULL);
|
||||
gu_pool_free(tmp_pool);
|
||||
gu_return_on_exn(err, NULL);
|
||||
return pgf;
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
#ifndef PGF_TYPE_H
|
||||
#define PGF_TYPE_H
|
||||
|
||||
typedef struct _Hypo {
|
||||
BindType bt;
|
||||
CId var;
|
||||
Type ty;
|
||||
} *Hypo;
|
||||
|
||||
typedef struct _Context {
|
||||
int size;
|
||||
struct _Hypo hypos[];
|
||||
} *Context;
|
||||
|
||||
struct _Type {
|
||||
Context hypos;
|
||||
CId cat;
|
||||
int nArgs;
|
||||
Expr args[];
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,248 +0,0 @@
|
||||
#include "../pgf.h"
|
||||
#include "data.h"
|
||||
#include "panic.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
static void freeCId(CId id) {
|
||||
free(id);
|
||||
}
|
||||
|
||||
static void freeCIdList(CIdList ids) {
|
||||
int i;
|
||||
for (i = 0; i < ids->count; i++) {
|
||||
freeCId(ids->names[i]);
|
||||
}
|
||||
free(ids);
|
||||
}
|
||||
|
||||
static void freeString(String str) {
|
||||
free(str);
|
||||
}
|
||||
|
||||
static void freeLiteral(Literal lit) {
|
||||
switch (lit->tag) {
|
||||
case LIT_STR:
|
||||
freeString (((LiteralStr) lit)->val);
|
||||
break;
|
||||
}
|
||||
free(lit);
|
||||
}
|
||||
|
||||
static void freeFlags(Flags flags) {
|
||||
int i;
|
||||
for (i = 0; i < flags->count; i++) {
|
||||
freeCId(flags->values[i].name);
|
||||
freeLiteral(flags->values[i].value);
|
||||
}
|
||||
free(flags);
|
||||
}
|
||||
|
||||
static void freeContext(Context ctxt);
|
||||
static void freeType(Type ty);
|
||||
|
||||
static void freeExpr(Expr e0) {
|
||||
|
||||
switch (e0->tag) {
|
||||
case TAG_ABS:
|
||||
{
|
||||
ExprAbs e = (ExprAbs) e0;
|
||||
freeCId(e->var);
|
||||
freeExpr(e->body);
|
||||
}
|
||||
break;
|
||||
case TAG_APP:
|
||||
{
|
||||
ExprApp e = (ExprApp) e0;
|
||||
freeExpr(e->left);
|
||||
freeExpr(e->right);
|
||||
}
|
||||
break;
|
||||
case TAG_LIT:
|
||||
{
|
||||
ExprLit e = (ExprLit) e0;
|
||||
freeLiteral(e->lit);
|
||||
}
|
||||
break;
|
||||
case TAG_MET:
|
||||
{
|
||||
ExprMeta e = (ExprMeta) e0;
|
||||
}
|
||||
break;
|
||||
case TAG_FUN:
|
||||
{
|
||||
ExprFun e = (ExprFun) e0;
|
||||
freeCId(e->fun);
|
||||
}
|
||||
break;
|
||||
case TAG_VAR:
|
||||
{
|
||||
ExprVar e = (ExprVar) e0;
|
||||
}
|
||||
break;
|
||||
case TAG_TYP:
|
||||
{
|
||||
ExprTyped e = (ExprTyped) e0;
|
||||
freeExpr(e->e);
|
||||
freeType(e->ty);
|
||||
}
|
||||
break;
|
||||
case TAG_IMP:
|
||||
{
|
||||
ExprImplArg e = (ExprImplArg) e0;
|
||||
freeExpr(e->e);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
__pgf_panic("Unknown expression tag");
|
||||
}
|
||||
|
||||
free(e0);
|
||||
}
|
||||
|
||||
static void freeType(Type ty) {
|
||||
freeContext(ty->hypos);
|
||||
freeCId(ty->cat);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < ty->nArgs; i++) {
|
||||
freeExpr(ty->args[i]);
|
||||
}
|
||||
|
||||
free(ty);
|
||||
}
|
||||
|
||||
static void freeHypo(Hypo hypo) {
|
||||
freeCId(hypo->var);
|
||||
freeType(hypo->ty);
|
||||
}
|
||||
|
||||
static void freeContext(Context ctxt) {
|
||||
int i;
|
||||
for (i = 0; i < ctxt->size; i++) {
|
||||
freeHypo(&ctxt->hypos[i]);
|
||||
}
|
||||
free(ctxt);
|
||||
}
|
||||
|
||||
static void freePatt(Patt p0) {
|
||||
switch (p0->tag) {
|
||||
case TAG_PAPP:
|
||||
{
|
||||
int i;
|
||||
PattApp p = (PattApp) p0;
|
||||
|
||||
freeCId(p->fun);
|
||||
for (i = 0; i < p->args.count; i++) {
|
||||
freePatt(p->args.pats[i]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TAG_PVAR:
|
||||
{
|
||||
PattVar p = (PattVar) p0;
|
||||
freeCId(p->var);
|
||||
}
|
||||
break;
|
||||
case TAG_PAT:
|
||||
{
|
||||
PattAt p = (PattAt) p0;
|
||||
freeCId(p->var);
|
||||
freePatt(p->pat);
|
||||
}
|
||||
break;
|
||||
case TAG_PWILD:
|
||||
{
|
||||
PattWild p = (PattWild) p0;
|
||||
}
|
||||
break;
|
||||
case TAG_PLIT:
|
||||
{
|
||||
PattLit p = (PattLit) p0;
|
||||
freeLiteral(p->lit);
|
||||
}
|
||||
break;
|
||||
case TAG_PIMP:
|
||||
{
|
||||
PattImplArg p = (PattImplArg) p0;
|
||||
freePatt(p->pat);
|
||||
}
|
||||
break;
|
||||
case TAG_PTILDE:
|
||||
{
|
||||
PattTilde p = (PattTilde) p0;
|
||||
freeExpr(p->e);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
__pgf_panic("Unknown pattern tag");
|
||||
}
|
||||
|
||||
free(p0);
|
||||
}
|
||||
|
||||
static void freePatts(Patts pats) {
|
||||
int i;
|
||||
for (i = 0; i < pats->count; i++) {
|
||||
freePatt(pats->pats[i]);
|
||||
}
|
||||
free(pats);
|
||||
}
|
||||
|
||||
static void freeEquations(Equations equs) {
|
||||
int i;
|
||||
for (i = 0; i < equs->count; i++) {
|
||||
freePatts(equs->equs[i].lhs);
|
||||
freeExpr(equs->equs[i].rhs);
|
||||
}
|
||||
free(equs);
|
||||
}
|
||||
|
||||
static void freeAbsFun(AbsFun fun) {
|
||||
freeCId(fun->name);
|
||||
freeType(fun->ty);
|
||||
freeEquations(fun->equs);
|
||||
}
|
||||
|
||||
static void freeAbsFuns(AbsFuns funs) {
|
||||
int i;
|
||||
for (i = 0; i < funs->count; i++) {
|
||||
freeAbsFun(&funs->lst[i]);
|
||||
}
|
||||
free(funs);
|
||||
}
|
||||
|
||||
static void freeAbsCat(AbsCat cat) {
|
||||
freeCId(cat->name);
|
||||
freeContext(cat->hypos);
|
||||
freeCIdList(cat->funs);
|
||||
}
|
||||
|
||||
static void freeAbsCats(AbsCats cats) {
|
||||
int i;
|
||||
for (i = 0; i < cats->count; i++) {
|
||||
freeAbsCat(&cats->lst[i]);
|
||||
}
|
||||
free(cats);
|
||||
}
|
||||
|
||||
static void freeAbstract(Abstract abstr) {
|
||||
freeCId(abstr->name);
|
||||
freeFlags(abstr->flags);
|
||||
freeAbsFuns(abstr->funs);
|
||||
freeAbsCats(abstr->cats);
|
||||
}
|
||||
|
||||
static void freeConcrete(Concrete concr) {
|
||||
// freeCId(concr->name);
|
||||
// freeFlags(concr->flags);
|
||||
}
|
||||
|
||||
void freePGF(PGF pgf) {
|
||||
int i;
|
||||
|
||||
freeFlags(pgf->flags);
|
||||
freeAbstract(&pgf->abstract);
|
||||
for (i = 0; i < pgf->nConcr; i++)
|
||||
freeConcrete(&pgf->concretes[i]);
|
||||
free(pgf);
|
||||
}
|
||||
Reference in New Issue
Block a user