Skip to content

Commit

Permalink
Support "xx$*{splat_expr}yy" syntax
Browse files Browse the repository at this point in the history
  • Loading branch information
ilyash committed Mar 25, 2017
1 parent f8c5669 commit aac844f
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 55 deletions.
2 changes: 2 additions & 0 deletions ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ char *NGS_AST_NODE_TYPES_NAMES[] = {
"param",
"str_comps",
"str_comp_imm",
"str_comp_expansion",
"str_comp_splat_expansion",
"null",
"true",
"false",
Expand Down
2 changes: 2 additions & 0 deletions ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ typedef enum {
PARAM_NODE,
STR_COMPS_NODE,
STR_COMP_IMM_NODE,
STR_COMP_EXPANSION_NODE,
STR_COMP_SPLAT_EXPANSION_NODE,
NULL_NODE,
TRUE_NODE,
FALSE_NODE,
Expand Down
58 changes: 44 additions & 14 deletions compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -708,26 +708,53 @@ void compile_main_section(COMPILATION_CONTEXT *ctx, ast_node *node, char **buf,
}
POP_IF_DONT_NEED_RESULT(*buf);
break;
case STR_COMPS_NODE:
case STR_COMPS_NODE: {
int have_splat = 0;
for(argc=0, ptr=node->first_child; ptr; argc++, ptr=ptr->next_sibling) {
compile_main_section(ctx, ptr, buf, idx, allocated, NEED_RESULT);
if(ptr->type != STR_COMP_IMM_NODE) {
OPCODE(*buf, OP_TO_STR);
if(ptr->type == STR_COMP_SPLAT_EXPANSION_NODE) {
have_splat = 1;
break;
}
}
switch(argc) {
case 0:
OPCODE(*buf, OP_PUSH_EMPTY_STR);
break;
case 1:
break;
default:
OPCODE(*buf, OP_PUSH_INT);
DATA_INT(*buf, argc);
OPCODE(*buf, OP_MAKE_STR);
if(have_splat) {
OPCODE(*buf, OP_PUSH_NULL);
for(argc=0, ptr=node->first_child; ptr; argc++, ptr=ptr->next_sibling) {
compile_main_section(ctx, ptr, buf, idx, allocated, NEED_RESULT);
switch(ptr->type) {
case STR_COMP_IMM_NODE: OPCODE(*buf, OP_MAKE_STR_IMM); break;
case STR_COMP_EXPANSION_NODE: OPCODE(*buf, OP_MAKE_STR_EXP); break;
case STR_COMP_SPLAT_EXPANSION_NODE: OPCODE(*buf, OP_MAKE_STR_SPLAT_EXP); break;
}
}
OPCODE(*buf, OP_PUSH_INT); DATA_INT(*buf, argc);
OPCODE(*buf, OP_MAKE_ARR);

OPCODE(*buf, OP_PUSH_INT); DATA_INT(*buf, 1);
// OPCODE(*buf, OP_MAKE_SPLAT_STR);
compile_identifier(ctx, buf, idx, "\"$*\"", OP_FETCH_LOCAL, OP_FETCH_UPVAR, OP_FETCH_GLOBAL);
OPCODE(*buf, OP_CALL);
} else {
for(argc=0, ptr=node->first_child; ptr; argc++, ptr=ptr->next_sibling) {
compile_main_section(ctx, ptr, buf, idx, allocated, NEED_RESULT);
if(ptr->type != STR_COMP_IMM_NODE) {
OPCODE(*buf, OP_TO_STR);
}
}
switch(argc) {
case 0:
OPCODE(*buf, OP_PUSH_EMPTY_STR);
break;
case 1:
break;
default:
OPCODE(*buf, OP_PUSH_INT);
DATA_INT(*buf, argc);
OPCODE(*buf, OP_MAKE_STR);
}
}
POP_IF_DONT_NEED_RESULT(*buf);
break;
}
case STR_COMP_IMM_NODE: {
size_t l = strlen(node->name);
if(l < 256) {
Expand All @@ -742,6 +769,9 @@ void compile_main_section(COMPILATION_CONTEXT *ctx, ast_node *node, char **buf,
}
break;
}
case STR_COMP_EXPANSION_NODE:
case STR_COMP_SPLAT_EXPANSION_NODE:
compile_main_section(ctx, node->first_child, buf, idx, allocated, need_result); break;
case NULL_NODE: if(need_result) { OPCODE(*buf, OP_PUSH_NULL); } break;
case TRUE_NODE: if(need_result) { OPCODE(*buf, OP_PUSH_TRUE); } break;
case FALSE_NODE: if(need_result) { OPCODE(*buf, OP_PUSH_FALSE); } break;
Expand Down
34 changes: 31 additions & 3 deletions lib/stdlib.ngs
Original file line number Diff line number Diff line change
Expand Up @@ -2111,9 +2111,9 @@ CHARS = ns {

# --- Constructors ---

# TODO: escaping?
doc TODO
F Str(s:Str) "'$s'"
doc No-op constructor
doc %RET - s
F Str(s:Str) s

doc Convert Null to string
doc %RET - the string "null"
Expand Down Expand Up @@ -2380,6 +2380,34 @@ F code(s:Str) {
"'${s}'"
}

doc String expansion handler. Called automatically for every double-quoted string that
doc has $* components.
doc %EX - "$*{ENV.PATH.split(":")}/od".filter(File(X)) # Find out where in PATH is the "od" binary
F '"$*"'(components:Arr) {
components.len() == 0 throws InvalidArgument("Must be one or more component")
c = components
c_len = c.len()
cached_str = c.map(F(elt:NgsStrComp) {
elt is not NgsStrCompSplatExp returns Str(elt.val)
})
collector {
F kern(acc:Arr, i:Int) {
if i == c_len {
collect(acc.join(''))
return
}
if c[i] is NgsStrCompSplatExp {
c[i].val.each(F(v) kern(acc + [v], i+1))
} else {
kern(acc + [cached_str[i]], i+1)
}
}
kern([], 0)
}
}

TEST "a$*{[1,2]}b$*{10..12}c" == ["a1b10c", "a1b11c", "a2b10c", "a2b11c"]


# === Logging and status reporting (WIP) =========

Expand Down
25 changes: 16 additions & 9 deletions syntax.leg
Original file line number Diff line number Diff line change
Expand Up @@ -172,14 +172,19 @@ ast_node *call_node_partial_application(ast_node *orig, int location[4]) {

// TODO: name the function
ast_node *string_node_partial_application(ast_node *orig, int location[4]) {
ast_node *p;
ast_node *p, *pp;
assert(orig->type == STR_COMPS_NODE);
for(p=orig->first_child; p; p=p->next_sibling) {
if(p->type == EXPRESSIONS_NODE && p->first_child && !p->first_child->next_sibling && p->first_child->type == IDENTIFIER_NODE) {
p = p->first_child;
if(p->type == STR_COMP_IMM_NODE) {
pp = p;
} else {
pp = p->first_child;
}
if(p->type == IDENTIFIER_NODE && strlen(p->name) == 1) {
if(p->name[0] == 'X' || p->name[0] == 'Y' || p->name[0] == 'Z') {
if(pp->type == EXPRESSIONS_NODE && pp->first_child && !pp->first_child->next_sibling && pp->first_child->type == IDENTIFIER_NODE) {
pp = pp->first_child;
}
if(pp->type == IDENTIFIER_NODE && strlen(pp->name) == 1) {
if(pp->name[0] == 'X' || pp->name[0] == 'Y' || pp->name[0] == 'Z') {
// wrap_in_func(ast_node *node, int location[4], char *docstring, int argc, ...) {
return wrap_in_func(orig, 0, location, "Partial application syntax - string", 1, 3, "X", "Any", "Y", "Any", "Z", "Any");
}
Expand Down Expand Up @@ -705,7 +710,7 @@ function-definition =

function-definition-name =
space+ i:identifier { $$ = i; }
| space? "'" <([-|=!@?<>~+*/%()$a-zA-Z0-9.`: ]|"["|"]")+> "'" {
| space? "'" <([-|=!@?<>~+*/%()$a-zA-Z0-9.`": ]|"["|"]")+> "'" {
MAKE_NODE(ret, IDENTIFIER_NODE);
ret->name = ngs_strdup(yytext);
$$ = ret;
Expand Down Expand Up @@ -1452,9 +1457,11 @@ string-dq-imm =
}

string-dq-dollar-expansion =
subshell
| "$" v:identifier { $$ = v; }
| "$" c:curly-code-block { $$ = c; }
s:subshell { MAKE_NODE(ret, STR_COMP_EXPANSION_NODE); append_ast_node_child(ret, s); $$ = ret; }
| "$" v:identifier { MAKE_NODE(ret, STR_COMP_EXPANSION_NODE); append_ast_node_child(ret, v); $$ = ret; }
| "$" c:curly-code-block { MAKE_NODE(ret, STR_COMP_EXPANSION_NODE); append_ast_node_child(ret, c); $$ = ret; }
| "$*" v:identifier { MAKE_NODE(ret, STR_COMP_SPLAT_EXPANSION_NODE); append_ast_node_child(ret, v); $$ = ret; }
| "$*" c:curly-code-block { MAKE_NODE(ret, STR_COMP_SPLAT_EXPANSION_NODE); append_ast_node_child(ret, c); $$ = ret; }

# https://en.wikipedia.org/wiki/Escape_sequences_in_C
string-escape = "\\" (
Expand Down
82 changes: 53 additions & 29 deletions vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,34 +78,37 @@ char *opcodes_names[] = {
/* 25 */ "MAKE_CLOSURE",
/* 26 */ "TO_STR",
/* 27 */ "MAKE_STR",
/* 28 */ "PUSH_EMPTY_STR",
/* 29 */ "GLOBAL_DEF_P",
/* 30 */ "LOCAL_DEF_P",
/* 31 */ "DEF_GLOBAL_FUNC",
/* 32 */ "DEF_LOCAL_FUNC",
/* 33 */ "FETCH_UPVAR",
/* 34 */ "STORE_UPVAR",
/* 35 */ "UPVAR_DEF_P",
/* 36 */ "DEF_UPVAR_FUNC",
/* 37 */ "MAKE_HASH",
/* 38 */ "TO_BOOL",
/* 39 */ "TO_ARR",
/* 40 */ "TO_HASH",
/* 41 */ "ARR_APPEND",
/* 42 */ "ARR_CONCAT",
/* 43 */ "GUARD",
/* 44 */ "TRY_START",
/* 45 */ "TRY_END",
/* 46 */ "ARR_REVERSE",
/* 47 */ "THROW",
/* 48 */ "MAKE_CMD",
/* 49 */ "SET_CLOSURE_NAME",
/* 50 */ "SET_CLOSURE_DOC",
/* 51 */ "HASH_SET",
/* 52 */ "HASH_UPDATE",
/* 53 */ "PUSH_KWARGS_MARKER",
/* 54 */ "MAKE_REDIR",
/* 55 */ "SUPER",
/* 28 */ "MAKE_STR_IMM",
/* 29 */ "MAKE_STR_EXP",
/* 30 */ "MAKE_STR_SPLAT_EXP",
/* 31 */ "PUSH_EMPTY_STR",
/* 32 */ "GLOBAL_DEF_P",
/* 33 */ "LOCAL_DEF_P",
/* 34 */ "DEF_GLOBAL_FUNC",
/* 35 */ "DEF_LOCAL_FUNC",
/* 36 */ "FETCH_UPVAR",
/* 37 */ "STORE_UPVAR",
/* 38 */ "UPVAR_DEF_P",
/* 39 */ "DEF_UPVAR_FUNC",
/* 40 */ "MAKE_HASH",
/* 41 */ "TO_BOOL",
/* 42 */ "TO_ARR",
/* 43 */ "TO_HASH",
/* 44 */ "ARR_APPEND",
/* 45 */ "ARR_CONCAT",
/* 46 */ "GUARD",
/* 47 */ "TRY_START",
/* 48 */ "TRY_END",
/* 49 */ "ARR_REVERSE",
/* 50 */ "THROW",
/* 51 */ "MAKE_CMD",
/* 52 */ "SET_CLOSURE_NAME",
/* 53 */ "SET_CLOSURE_DOC",
/* 54 */ "HASH_SET",
/* 55 */ "HASH_UPDATE",
/* 56 */ "PUSH_KWARGS_MARKER",
/* 57 */ "MAKE_REDIR",
/* 58 */ "SUPER",
};


Expand Down Expand Up @@ -2230,13 +2233,21 @@ void vm_init(VM *vm, int argc, char **argv) {
SETUP_TYPE_FIELD(Stat, st_blksize, 8);
SETUP_TYPE_FIELD(Stat, st_blocks, 9);

// "NgsStrImm${NgsStrExp}$*{NgsStrSplatExp}"
MKTYPE(NgsStrComp);
MKSUBTYPE(NgsStrCompImm, NgsStrComp);
MKSUBTYPE(NgsStrCompExp, NgsStrComp);
MKSUBTYPE(NgsStrCompSplatExp, NgsStrComp);

#undef SETUP_RANGE_TYPE
#undef SETUP_TYPE_FIELD
#undef MKSUBTYPE
#undef MKTYPE

// Why is it here? Consider removing - start
vm->eqeq = make_array(0);
set_global(vm, "==", vm->eqeq);
// Why is it here? Consider removing - end

register_global_func(vm, 0, "==", &native_false, 2, "a", vm->Any, "b", vm->Any);
_doc(vm, "%RET", "false");
Expand Down Expand Up @@ -3560,6 +3571,19 @@ METHOD_RESULT vm_run(VM *vm, CTX *ctx, IP ip, VALUE *result) {
ip += sizeof(uint32_t) + *(uint32_t *) &vm->bytecode[ip];
PUSH(v);
goto main_loop;
#define OP_MAKE_STR_(type_name) \
EXPECT_STACK_DEPTH(1); \
v = make_normal_type_instance(vm->type_name); \
set_normal_type_instance_attribute(v, make_string("val"), TOP); \
TOP = v; \
goto main_loop;
case OP_MAKE_STR_IMM:
OP_MAKE_STR_(NgsStrCompImm);
case OP_MAKE_STR_EXP:
OP_MAKE_STR_(NgsStrCompExp);
case OP_MAKE_STR_SPLAT_EXP:
OP_MAKE_STR_(NgsStrCompSplatExp);
#undef OP_MAKE_STR_
case OP_DUP:
DUP;
goto main_loop;
Expand All @@ -3581,7 +3605,7 @@ METHOD_RESULT vm_run(VM *vm, CTX *ctx, IP ip, VALUE *result) {
// Arg: offset
// In ... n
// Out: ...
// Effect: bytecode[offset] <- n
// Effect: bytecode[ip+offset] <- n
POP(v);
ARG(po, PATCH_OFFSET);
#ifdef DO_NGS_DEBUG
Expand Down
8 changes: 8 additions & 0 deletions vm.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,11 @@ typedef struct {

VALUE Stat;

VALUE NgsStrComp;
VALUE NgsStrCompImm;
VALUE NgsStrCompExp;
VALUE NgsStrCompSplatExp;

VALUE impl_not_found_handler;
VALUE global_not_found_handler;
VALUE init;
Expand Down Expand Up @@ -295,6 +300,9 @@ enum opcodes {
OP_MAKE_CLOSURE,
OP_TO_STR,
OP_MAKE_STR,
OP_MAKE_STR_IMM,
OP_MAKE_STR_EXP,
OP_MAKE_STR_SPLAT_EXP,
OP_PUSH_EMPTY_STR,
OP_GLOBAL_DEF_P,
OP_LOCAL_DEF_P,
Expand Down

0 comments on commit aac844f

Please sign in to comment.