diff options
| -rw-r--r-- | examples/fib.fwd | 12 | ||||
| -rw-r--r-- | examples/uniq.fwd | 16 | ||||
| -rw-r--r-- | include/fwd/ast.h | 33 | ||||
| -rw-r--r-- | lib/fwdlib.hpp | 1 | ||||
| -rw-r--r-- | src/ast.c | 1 | ||||
| -rw-r--r-- | src/lexer.l | 5 | ||||
| -rw-r--r-- | src/lower.c | 118 | ||||
| -rw-r--r-- | src/parser.y | 30 | 
8 files changed, 164 insertions, 52 deletions
| diff --git a/examples/fib.fwd b/examples/fib.fwd index 8b0e055..4eb2e60 100644 --- a/examples/fib.fwd +++ b/examples/fib.fwd @@ -5,19 +5,19 @@   * bifurcating nature of fibonacci just gets mapped to a linear sequence of   * calls? */ -fib(n, res) +fib(int n, (int) res)  { -	fwd_if(n < 2) => { +	if n < 2 {  		res(1); -	} => { -		fib(n - 1) => f1; -		fib(n - 2) => f2; +	} else { +		fib(n - 1) => int f1; +		fib(n - 2) => int f2;  		res(f1 + f2);  	}  }  main()  { -	fib(6) => n; +	fib(6) => int n;  	fwd_println(n);  } diff --git a/examples/uniq.fwd b/examples/uniq.fwd index 490a702..c043a89 100644 --- a/examples/uniq.fwd +++ b/examples/uniq.fwd @@ -2,15 +2,13 @@  /* at some point I'll probably add in a type system as well, but for now let's   * pretend we're static-dynamic (or dynamic at compiletime? dunno) */ -readlines(set, next) +readlines(unordered_set![string] set, (unordered_set![string]) next)  { -	/* option![str] */ -	fwd_getline() => line; +	fwd_getline() => optional![string] line; -	/* unwraps option![str] -> str */ -	fwd_some(line) => line { +	fwd_some(line) => string line {  		/* we had something in our option */ -		fwd_insert(set, line) => set; +		fwd_insert(set, line) => unordered_set![string] set;  		/* at the moment the only supported looping construct is  		 * recursion */ @@ -25,9 +23,9 @@ main()  {  	/* fwdlib.hpp uses namespace std, not good practice but allows us to do  	 * stuff like this: */ -	unordered_set![string]{} => set; -	readlines(set) => set; -	fwd_foreach(set) => node { +	unordered_set![string]{} => unordered_set![string] set; +	readlines(set) => unordered_set![string] set; +	fwd_foreach(set) => string node {  		fwd_println(node);  	}  } diff --git a/include/fwd/ast.h b/include/fwd/ast.h index c124ac1..34fcd64 100644 --- a/include/fwd/ast.h +++ b/include/fwd/ast.h @@ -30,7 +30,7 @@ struct src_loc {  struct ast;  enum type_kind { -	TYPE_ID = 1, TYPE_CONSTRUCT +	TYPE_ID = 1, TYPE_CONSTRUCT, TYPE_REF, TYPE_PTR, TYPE_CALLABLE  };  struct type { @@ -52,6 +52,8 @@ struct type {  enum ast_kind {  	/** Creating new variable. */  	AST_LET = 1, +	/** If statement */ +	AST_IF,  	/** Call procedure. */  	AST_CALL,  	/** Procedure definition. */ @@ -248,6 +250,17 @@ static inline bool is_const(struct ast *x)  #define tgen_construct(id, args, loc) \  	tgen_type(TYPE_CONSTRUCT, args, id, loc) +#define tptr_base(x) return_t0(x, TYPE_PTR) +#define tgen_ptr(base, loc) \ +	tgen_type(TYPE_PTR, base, NULL, loc) + +#define tref_base(x) return_t0(x, TYPE_REF) +#define tgen_ref(base, loc) \ +	tgen_type(TYPE_REF, base, NULL, loc) + +#define tcallable_args(x) return_t0(x, TYPE_CALLABLE) +#define tgen_callable(args, loc) \ +	tgen_type(TYPE_CALLABLE, args, NULL, loc)  #define closure_bindings(x) return_a0(x, AST_CLOSURE)  #define closure_body(x) return_a1(x, AST_CLOSURE) @@ -288,8 +301,8 @@ static inline bool is_const(struct ast *x)  #define var_id(x) return_s(x, AST_VAR_DEF)  #define var_type(x) return_t2(x, AST_VAR_DEF)  #define var_init(x) return_a0(x, AST_VAR_DEF) -#define gen_var(id, loc) \ -	gen_ast(AST_VAR_DEF, NULL, NULL, NULL, NULL, NULL, id, 0, 0., loc) +#define gen_var(id, type, loc) \ +	gen_ast(AST_VAR_DEF, NULL, NULL, NULL, NULL, type, id, 0, 0., loc)  #define block_body(x) return_a0(x, AST_BLOCK)  #define gen_block(body, loc) \ @@ -315,10 +328,10 @@ static inline bool is_const(struct ast *x)  #define gen_const_bool(i, loc) \  	gen_ast(AST_CONST_BOOL, NULL, NULL, NULL, NULL, NULL, NULL, i, 0., loc) -#define let_id(x) return_s(x, AST_LET) -#define let_expr(x) return_a0(x, AST_LET) -#define gen_let(id, from, loc) \ -	gen_str1(AST_LET, id, from, loc) +#define let_var(x) return_a0(x, AST_LET) +#define let_expr(x) return_a1(x, AST_LET) +#define gen_let(var, from, loc) \ +	gen2(AST_LET, var, from, loc)  #define init_args(x) return_t2(x, AST_INIT)  #define init_body(x) return_a0(x, AST_INIT) @@ -326,6 +339,12 @@ static inline bool is_const(struct ast *x)  #define gen_init(id, targs, body, loc) \  	gen_str_type1(AST_INIT, id, targs, body, loc) +#define if_cond(x) return_a0(x, AST_IF) +#define if_body(x) return_a1(x, AST_IF) +#define if_else(x) return_a2(x, AST_IF) +#define gen_if(cond, body, els, loc) \ +	gen3(AST_IF, cond, body, els, loc) +  #define id_str(x) return_s(x, AST_ID)  #define gen_id(id, loc) \  	gen_str(AST_ID, id, loc) diff --git a/lib/fwdlib.hpp b/lib/fwdlib.hpp index 034c91a..3efac61 100644 --- a/lib/fwdlib.hpp +++ b/lib/fwdlib.hpp @@ -4,6 +4,7 @@  #include <string>  #include <optional>  #include <iostream> +#include <functional>  #include <unordered_map>  #include <unordered_set> @@ -174,6 +174,7 @@ void ast_dump(int depth, struct ast *n)  #define DUMP(x) case x: dump(depth, #x); break;  	switch (n->k) {  	DUMP(AST_CLOSURE); +	DUMP(AST_IF);  	DUMP(AST_LET);  	DUMP(AST_INIT);  	DUMP(AST_CALL); diff --git a/src/lexer.l b/src/lexer.l index fe748e2..a150798 100644 --- a/src/lexer.l +++ b/src/lexer.l @@ -125,6 +125,11 @@ STRING		\"(\\.|[^"\\])*\"  "<<"		{return LSHIFT;}  ">>"		{return RSHIFT;} +"if"		{return IF;} +"else"		{return ELSE;} + +"mut"		{return MUT;} +  {STRING} {  	/* seems risky, I know, but letting the parser choose when to allocate a  	 * new string seems to help with syntax error cleanup */ diff --git a/src/lower.c b/src/lower.c index 46ce2c3..cf36fb0 100644 --- a/src/lower.c +++ b/src/lower.c @@ -31,10 +31,14 @@ static void indent(struct state *state)  		putchar(' ');  } +static int lower_var(struct ast *expr); +  static int lower_expr(struct state *state, struct ast *expr);  static int lower_block(struct state *state, struct ast *block);  static int lower_closure(struct state *state, struct ast *closure); +static int lower_statement(struct state *state, struct ast *stmt); +static int lower_type(struct type *type);  static int lower_types(struct type *types);  static int lower_binop(struct state *state, struct ast *binop) @@ -105,14 +109,8 @@ static int lower_exprs(struct state *state, struct ast *exprs)  	return 0;  } -static int lower_type(struct type *type) +static int lower_type_construct(struct type *type)  { -	if (type->k == TYPE_ID) { -		printf("%s", tid_str(type)); -		return 0; -	} - -	assert(type->k == TYPE_CONSTRUCT);  	printf("%s", tconstruct_id(type));  	printf("<"); @@ -123,6 +121,51 @@ static int lower_type(struct type *type)  	return 0;  } +static int lower_type_callable(struct type *type) +{ +	printf("std::function<void("); + +	if (lower_types(tcallable_args(type))) +		return -1; + +	printf(")>"); +	return 0; +} + +static int lower_type_ref(struct type *type) +{ +	if (lower_type(tref_base(type))) +		return -1; + +	printf("&"); +	return 0; +} + +static int lower_type_ptr(struct type *type) +{ +	if (lower_type(tptr_base(type))) +		return -1; + +	printf("*"); +	return 0; +} + +static int lower_type(struct type *type) +{ +	switch (type->k) { +	case TYPE_ID: printf("%s", tid_str(type)); return 0; +	case TYPE_CONSTRUCT: return lower_type_construct(type); +	case TYPE_CALLABLE: return lower_type_callable(type); +	case TYPE_REF: return lower_type_ref(type); +	case TYPE_PTR: return lower_type_ptr(type); +	default: +		internal_error("missing type lowering"); +		return -1; +	} + +	return 0; +} +  static int lower_types(struct type *types)  {  	if (!types) @@ -250,7 +293,11 @@ static int lower_call(struct state *state, struct ast *call)  static int lower_let(struct state *state, struct ast *let)  { -	printf("auto %s = ", let_id(let)); +	if (lower_var(let_var(let))) +		return -1; + +	printf(" = "); +  	if (lower_expr(state, let_expr(let)))  		return -1; @@ -258,11 +305,34 @@ static int lower_let(struct state *state, struct ast *let)  	return 0;  } +static int lower_if(struct state *state, struct ast *stmt) +{ +	printf("if ("); +	if (lower_expr(state, if_cond(stmt))) +		return -1; + +	printf(") "); + +	if (lower_block(state, if_body(stmt))) +		return -1; + +	if (!if_else(stmt)) +		return 0; + +	printf(" else "); +	if (lower_block(state, if_else(stmt))) +		return -1; + +	printf("\n"); +	return 0; +} +  static int lower_statement(struct state *state, struct ast *stmt)  {  	switch (stmt->k) { -	case AST_LET: return lower_let(state, stmt); -	case AST_CALL: return lower_call(state, stmt); +	case AST_LET:	return lower_let(state, stmt); +	case AST_CALL:	return lower_call(state, stmt); +	case AST_IF:	return lower_if(state, stmt);  	default:  		internal_error("missing statement lowering");  		return -1; @@ -290,15 +360,27 @@ static int lower_block(struct state *state, struct ast *block)  	return 0;  } -static int lower_params(struct ast *params) +static int lower_var(struct ast *var) +{ +	if (lower_type(var_type(var))) +		return -1; + +	printf(" %s", var_id(var)); +	return 0; +} + +static int lower_vars(struct ast *vars)  { -	if (!params) +	if (!vars)  		return 0; -	printf("auto %s", var_id(params)); +	if (lower_var(vars)) +		return -1; -	foreach_node(param, params->n) { -		printf(", auto %s", var_id(param)); +	foreach_node(var, vars->n) { +		printf(", "); +		if (lower_var(var)) +			return -1;  	}  	return 0; @@ -307,7 +389,7 @@ static int lower_params(struct ast *params)  static int lower_closure(struct state *state, struct ast *closure)  {  	printf("[&]("); -	if (lower_params(closure_bindings(closure))) +	if (lower_vars(closure_bindings(closure)))  		return -1;  	printf(")"); @@ -327,7 +409,7 @@ static int lower_proto(struct ast *proc)  	printf("%s(", proc_id(proc)); -	if (lower_params(proc_params(proc))) +	if (lower_vars(proc_params(proc)))  		return -1;  	printf(");\n\n"); @@ -343,7 +425,7 @@ static int lower_proc(struct ast *proc)  	printf("%s(", proc_id(proc)); -	if (lower_params(proc_params(proc))) +	if (lower_vars(proc_params(proc)))  		return -1;  	printf(")\n"); diff --git a/src/parser.y b/src/parser.y index ccff211..97a700e 100644 --- a/src/parser.y +++ b/src/parser.y @@ -69,7 +69,9 @@  %token RBRACE "}"  %token LBRACKET "["  %token RBRACKET "]" -%token AS "as" +%token IF "if" +%token ELSE "else" +%token MUT "mut"  %token DOT "."  %token SCOPE "::"  %token FATARROW "=>" @@ -94,11 +96,12 @@  %nterm <node> vars exprs statements closures  %nterm <node> opt_vars opt_exprs opt_statements  %nterm <node> rev_vars rev_exprs rev_closures rev_statements -%nterm <node> let unop binop construct +%nterm <node> let if unop binop construct  %nterm <type> type rev_types types opt_types +  %{  /** Modifies the signature of yylex to fit our parser better. */ @@ -176,7 +179,7 @@ static char *strip(const char *s);  %start input;  %%  var -	: ID { $$ = gen_var($1, src_loc(@$)); } +	: type ID { $$ = gen_var($2, $1, src_loc(@$)); }  rev_vars  	: rev_vars "," var { $$ = $3; $$->n = $1; } @@ -219,6 +222,9 @@ type  	| APPLY "[" opt_types "]" {  		$$ = tgen_construct($[APPLY], $[opt_types], src_loc(@$));  	} +	| "(" opt_types ")" { $$ = tgen_callable($2, src_loc(@$)); } +	| "&" type { $$ = tgen_ref($2, src_loc(@$)); } +	| "*" type { $$ = tgen_ptr($2, src_loc(@$)); }  rev_types  	: rev_types "," type { $$ = $3; $3->n = $$; } @@ -290,11 +296,17 @@ call  	}  let -	: expr "=>" ID ";" { $$ = gen_let($3, $1, src_loc(@$)); } +	: expr "=>" var ";" { $$ = gen_let($3, $1, src_loc(@$)); } + +if +	: "if" expr body { $$ = gen_if($2, $3, NULL, src_loc(@$)); } +	| "if" expr body "else" body { $$ = gen_if($2, $3, $5, src_loc(@$)); } +	| "if" expr body "else" if { $$ = gen_if($2, $3, $5, src_loc(@$)); }  statement  	: call  	| let +	| if  	| ";" { $$ = gen_empty(src_loc(@$)); }  rev_statements @@ -419,14 +431,8 @@ static char *strip(const char *str)  	/* skip quotation marks */  	size_t j = 0; -	for (size_t i = 1; i < len - 2; ++i) { -		char c = str[i]; - -		if (c == '\\') -			c = match_escape(str[++i]); - -		buf[j++] = c; -	} +	for (size_t i = 1; i < len - 2; ++i) +		buf[j++] = str[i];  	buf[j] = 0;  	free((void *)str); | 
