void test_equals_string() { String str = copy_string("abc"); assert(equals_string(str, "abc")); assert(equals_string(NULL, NULL)); assert(!equals_string(str, NULL)); assert(!equals_string(NULL, str)); }
static statement *parse_func_call(linked_list *tokens) { linked_list *accumulator = ll_new(); linked_iter iterator = ll_iter_head(tokens); statement *call = new(call); call->type = FUNC_CALL; call->data = ((parse_token*)ll_iter_next(&iterator))->data; call->children = ll_new(); int paren_level = 0; ll_iter_next(&iterator); //Discard opening parenthesis for(parse_token *current = ll_iter_next(&iterator); ll_iter_has_next(&iterator); current = ll_iter_next(&iterator)) { if(paren_level == 0 && (equals_string(current->data, ",") || equals_string(current->data, ")"))) { statement *parameter = parse_simple_expression(accumulator); if(parameter != NULL) ll_add_last(call->children, parameter); ll_clear(accumulator); } else { ll_add_last(accumulator, current); } if(equals_string(current->data, "(")) paren_level += 1; else if(equals_string(current->data, ")")) paren_level -= 1; } statement *parameter = parse_simple_expression(accumulator); if(parameter != NULL) ll_add_last(call->children, parameter); ll_destroy(accumulator); return call; }
void parse_string_as_argument_list(caValue* str, List* output) { // Read the tokens as a space-seperated list of strings. // TODO is to be more smart about word boundaries: spaces inside // quotes or parentheses shouldn't break apart items. TokenStream tokens; tokens.reset(as_cstring(str)); Value itemInProgress; set_string(&itemInProgress, ""); while (!tokens.finished()) { if (tokens.nextIs(tok_Whitespace)) { if (!equals_string(&itemInProgress, "")) { copy(&itemInProgress, list_append(output)); set_string(&itemInProgress, ""); } } else { string_append(&itemInProgress, tokens.nextStr().c_str()); } tokens.consume(); } if (!equals_string(&itemInProgress, "")) { copy(&itemInProgress, list_append(output)); set_string(&itemInProgress, ""); } }
String eval_sys(Mapping *m, Statement *source, Queue *repQueue) { String prepare = copy_string(m->sys->prepare); String eval = copy_string(m->sys->eval); Mapping *mapping = NULL; String* array = NULL; String* arraySource = NULL; String* arrayTarget = NULL; String prepareSource; String prepareTarget; String sourceFuncMacro; String sourceMacro; String targetFuncMacro; String targetMacro; if (!equals_string(prepare, "NIL")) { mapping = alloc_mapping(); mapping->sys = NULL; if (strcmp(m->sys->name, DEF_MACRO) == 0) { mapping->isMacro = TRUE; } else { mapping->isMacro = FALSE; } array = split_string_once(prepare, '>'); prepareSource = array[0]; prepareTarget = array[1]; arraySource = split_string_once(prepareSource, ','); sourceFuncMacro = trim_string(arraySource[0]); sourceMacro = trim_string(arraySource[1]); mapping->source = parse_macro(repQueue, sourceMacro); mapping->sourceFunc = parse_macro(repQueue, sourceFuncMacro); mapping->sourceStatement = parse(mapping->source); mapping->starter = to_dfa(mapping->sourceStatement); arrayTarget = split_string_once(prepareTarget, ','); targetFuncMacro = trim_string(arrayTarget[0]); targetMacro = trim_string(arrayTarget[1]); mapping->target = parse_macro(repQueue, targetMacro); mapping->targetFunc = parse_macro(repQueue, targetFuncMacro); mapping->targetStatement = parse(mapping->target); //enqueue(get_mappings(), mapping); add_mapping_to_trie(mapping); } if (!equals_string(eval, "NIL")) { return parse_macro(repQueue, eval); } else { return ""; } }
static import_declaration *parse_import(parse_source *source) { parse_token current = get_mandatory_token(source); import_declaration *imp = new(imp); imp->name = current.data; current = get_mandatory_token(source); if(!equals_string(current.data, ";")) { semantic_error("Expected semicolon after import statement", current.origin); } return imp; }
static enum_declaration *parse_enum(parse_source *source) { enum_declaration *dec = new(dec); parse_token current = get_mandatory_token(source); dec->name = current.data; dec->options = ll_new(); while(!equals_string(get_mandatory_token(source).data, "}")) { statement *expr = new(expr); current = get_mandatory_token(source); expr->data = current.data; ll_add_last(dec->options, expr); } return dec; }
int main(int argc, char **argv) { Scheme *sc = alloc_scheme(); Statement *st = NULL; String scheme = NULL; if (!scheme_init(sc)) { fprintf(stderr, "Initialize scheme environment error!\n"); return 1; } if (!funny_init()) { fprintf(stderr, "Initialize funny environment error!\n"); return 1; } printf("Welcome to FUNNY programming world. Type {exit} to exit.\n"); while (TRUE) { printf("> "); st = read_statement(stdin); if (empty_statement(st)) { printf("can't parse the statement.\n"); continue; } wait_to_exit(st); scheme = match(st); if (equals_string(scheme, "")) continue; //#ifdef DEBUG printf("TARGET: %s\n", scheme); //#endif Cell* result = eval(sc, scheme); printf("%s\n", cell2str(sc, result)); } return 0; }
void do_admin_command(caValue* input, caValue* reply) { // Identify the command int first_space = string_find_char(input, 0, ' '); if (first_space == -1) first_space = string_length(input); Value command; string_slice(input, 0, first_space, &command); set_null(reply); if (equals_string(&command, "add_lib_path")) { //List args; //parse_tokens_as_argument_list(&tokens, &args); } else if (equals_string(&command, "file")) { List args; parse_string_as_argument_list(input, &args); do_file_command(&args, reply); } else if (equals_string(&command, "echo")) { List args; parse_string_as_argument_list(input, &args); do_echo(&args, reply); } else if (equals_string(&command, "write_block")) { int nextSpace = string_find_char(input, first_space+1, ' '); if (nextSpace == -1) { set_string(reply, "Syntax error, not enough arguments"); return; } Value blockName; string_slice(input, first_space+1, nextSpace, &blockName); Value contents; string_slice(input, nextSpace+1, -1, &contents); do_write_block(&blockName, &contents, reply); } else if (equals_string(&command, "update_file")) { int nextSpace = string_find_char(input, first_space+1, ' '); if (nextSpace == -1) { set_string(reply, "Syntax error, not enough arguments"); return; } Value filename; string_slice(input, first_space+1, nextSpace, &filename); Value contents; string_slice(input, nextSpace+1, -1, &contents); do_update_file(&filename, &contents, reply); } else if (equals_string(&command, "source_repro")) { List args; parse_string_as_argument_list(input, &args); Block block; load_script(&block, as_cstring(args[1])); std::cout << get_block_source_text(&block); } else if (equals_string(&command, "dump_stats")) { perf_stats_dump(); std::cout << ":done" << std::endl; } else { set_string(reply, "Unrecognized command: "); string_append(reply, &command); } }
static statement *parse_simple_expression(linked_list *tokens) { while(equals_string(((parse_token*)ll_get_first(tokens))->data, "(") && equals_string(((parse_token*)ll_get_last(tokens))->data, ")")) { ll_remove_first(tokens); ll_remove_last(tokens); } int size = ll_size(tokens); switch(size) { case 0: return NULL; case 1: return parse_single_token(tokens); default: { if(size == 2) { parse_token *token = ll_get_first(tokens); bool isStack; if((isStack = equals_string(token->data, "new")) || equals_string(token->data, "newref")) { statement *expression = new(expression); expression->children = ll_new(); expression->type = isStack ? STACK_INIT : HEAP_INIT; linked_list *name = ll_duplicate(tokens); ll_remove_first(name); ll_add_first(expression->children, parse_simple_expression(name)); return expression; } } int paren_level = 1; linked_iter iterator = ll_iter_head(tokens); bool is_index = true, is_call = true; ll_iter_next(&iterator); parse_token *second = ll_iter_next(&iterator); if(equals_string(second->data, "(")) { is_index = false; } else if(equals_string(second->data, "[")) { is_call = false; } else { is_index = is_call = false; } while((is_index || is_call) && ll_iter_has_next(&iterator)) { parse_token *token = ll_iter_next(&iterator); if(equals_string(token->data, "(") || equals_string(token->data, "[")) { paren_level += 1; } else if(paren_level == 0) { is_index = false; is_call = false; } else if(equals_string(token->data, ")") || equals_string(token->data, "]")) { paren_level -= 1; } } if(is_index) { return parse_array_index(tokens); } else if(is_call) { return parse_func_call(tokens); } linked_list *operator = get_node(); linked_iter level = ll_iter_head(operator); while(ll_iter_has_next(&level)) { int paren_level = 0; linked_list *currentLevel = ll_iter_next(&level); linked_iter iterator = ll_iter_head(tokens); for(parse_token *current = ll_iter_next(&iterator); ll_iter_has_next(&iterator); current = ll_iter_next(&iterator)) { char currentChar = current->data.data[0]; if(currentChar == '(') { paren_level += 1; } else if(currentChar == ')') { paren_level -= 1; } if(paren_level != 0) continue; linked_iter innerMost = ll_iter_head(currentLevel); while(ll_iter_has_next(&innerMost)) { operator_node *currentOperator = ll_iter_next(&innerMost); if(equals_string(current->data, currentOperator->data)) { if(!is_unary_operator(new_slice(currentOperator->data))) { linked_list *op1 = ll_duplicate(tokens); while(ll_get_last(op1) != current) ll_remove_last(op1); ll_remove_last(op1); linked_list *op2 = tokens; while(ll_get_first(op2) != current) ll_remove_first(op2); ll_remove_first(op2); statement *expression = new(expression); expression->data = new_slice(""); expression->children = ll_new(); expression->type = currentOperator->operatorType; statement *op1_exp = parse_simple_expression(op1); statement *op2_exp = parse_simple_expression(op2); ll_add_last(expression->children, op1_exp); ll_add_last(expression->children, op2_exp); return expression; } else { statement *expression = new(expression); expression->data = new_slice(currentOperator->data); expression->type = currentOperator->operatorType; linked_list *rest = ll_duplicate(tokens); ll_remove_first(rest); expression->children = ll_new(); ll_add_first(expression->children, parse_simple_expression(rest)); return expression; } } } } } return NULL; } } }
static statement *get_expression(parse_source *source, int *indent) { parse_token token = get_mandatory_token(source); if(equals_string(token.data, "{")) { statement *expression = new(expression); expression->type = BLOCK; expression->children = ll_new(); expression->data = new_slice(""); int finished = *indent; *indent += 1; while(*indent != finished) { statement *state = get_expression(source, indent); if(state != NULL) ll_add_last(expression->children, state); } return expression; } else if(equals_string(token.data, "}")) { *indent -= 1; return NULL; } else if(equals_string(token.data, "if") || equals_string(token.data, "while") || equals_string(token.data, "for")) { statement *expression = new(expression); if(equals_string(token.data, "if")) expression->type = IF; else if(equals_string(token.data, "while")) expression->type = WHILE; else if(equals_string(token.data, "for")) expression->type = FOR; expression->children = ll_new(); expression->data = new_slice(""); ll_add_last(expression->children, get_expression(source, indent)); //Add the header if(expression->type == FOR) { ll_add_last(expression->children, get_expression(source, indent)); //Add the header ll_add_last(expression->children, get_expression(source, indent)); //Add the header } ll_add_last(expression->children, get_expression(source, indent)); //Add the body if(expression->type == IF) { parse_token next = peek_mandatory_token(source); if(equals_string(next.data, "else")) { get_mandatory_token(source); statement *elseState = new(elseState); elseState->type = ELSE; elseState->children = ll_new(); elseState->data = new_slice(""); ll_add_last(expression->children, elseState); ll_add_first(elseState->children, get_expression(source, indent)); } } return expression; } else if(equals_string(token.data, "break") || equals_string(token.data, "continue")) { statement *expression = new(expression); expression->type = equals_string(token.data, "break") ? BREAK : CONTINUE; expression->data = new_slice(""); expression->children = NULL; parse_token next = get_mandatory_token(source); if(!equals_string(next.data, ";")) semantic_error("Expected a semicolon after a break or continue", next.origin); return expression; } else if(equals_string(token.data, "return")) { statement *expression = new(expression); expression->type = RETURN; expression->data = new_slice(""); expression->children = ll_new(); ll_add_last(expression->children, get_expression(source, indent)); return expression; } else { linked_list *accumulator = ll_new(); parse_token next = token; while(true) { parse_token *allocated = new(allocated); *allocated = token; ll_add_last(accumulator, allocated); next = peek_mandatory_token(source); if(equals_string(next.data, "{") || equals_string(next.data, "}")) break; if(equals_string(next.data, ";")) { get_mandatory_token(source); break; } token = get_mandatory_token(source); } statement *expression = parse_simple_expression(accumulator); ll_delete_all(accumulator); return expression; } }