Add !!
statement for printing text
This commit is contained in:
parent
d073c10137
commit
9d9fe12987
1
ast.c
1
ast.c
@ -137,6 +137,7 @@ CORD ast_to_xml(ast_t *ast)
|
||||
optional_tagged("combination", data.combination), optional_tagged("fallback", data.fallback))
|
||||
T(Skip, "<Skip>%r</Skip>", data.target)
|
||||
T(Stop, "<Stop>%r</Stop>", data.target)
|
||||
T(PrintStatement, "<PrintStatement>%r</PrintStatement>", ast_list_to_xml(data.to_print))
|
||||
T(Pass, "<Pass/>")
|
||||
T(Return, "<Return>%r</Return>", ast_to_xml(data.value))
|
||||
T(Extern, "<Extern name=\"%s\">%r</Extern>", data.name, type_ast_to_xml(data.type))
|
||||
|
5
ast.h
5
ast.h
@ -99,7 +99,7 @@ typedef enum {
|
||||
Unknown = 0,
|
||||
Nil, Bool, Var,
|
||||
Int, Num,
|
||||
TextLiteral, TextJoin,
|
||||
TextLiteral, TextJoin, PrintStatement,
|
||||
Declare, Assign,
|
||||
BinaryOp, UpdateAssign,
|
||||
Length, Not, Negative, HeapAllocate, StackReference,
|
||||
@ -151,6 +151,9 @@ struct ast_s {
|
||||
const char *lang;
|
||||
ast_list_t *children;
|
||||
} TextJoin;
|
||||
struct {
|
||||
ast_list_t *to_print;
|
||||
} PrintStatement;
|
||||
struct {
|
||||
ast_t *var;
|
||||
ast_t *value;
|
||||
|
20
compile.c
20
compile.c
@ -17,6 +17,7 @@
|
||||
static CORD compile_to_pointer_depth(env_t *env, ast_t *ast, int64_t target_depth, bool allow_optional);
|
||||
static env_t *with_enum_scope(env_t *env, type_t *t);
|
||||
static CORD compile_math_method(env_t *env, ast_t *ast, binop_e op, ast_t *lhs, ast_t *rhs, type_t *required_type);
|
||||
static CORD compile_string(env_t *env, ast_t *ast, CORD color);
|
||||
|
||||
static bool promote(env_t *env, CORD *code, type_t *actual, type_t *needed)
|
||||
{
|
||||
@ -679,6 +680,23 @@ CORD compile_statement(env_t *env, ast_t *ast)
|
||||
code_err(ast, "I couldn't figure out how to make this stop work!");
|
||||
}
|
||||
case Pass: return ";";
|
||||
case PrintStatement: {
|
||||
ast_list_t *to_print = Match(ast, PrintStatement)->to_print;
|
||||
if (!to_print)
|
||||
return CORD_EMPTY;
|
||||
|
||||
CORD code = "say(CORD_all(";
|
||||
for (ast_list_t *chunk = to_print; chunk; chunk = chunk->next) {
|
||||
type_t *t = get_type(env, chunk->ast);
|
||||
if (t->tag == TextType && !Match(t, TextType)->lang) {
|
||||
code = CORD_cat(code, compile(env, chunk->ast));
|
||||
} else {
|
||||
code = CORD_cat(code, compile_string(env, chunk->ast, "USE_COLOR"));
|
||||
}
|
||||
if (chunk->next) code = CORD_cat(code, ", ");
|
||||
}
|
||||
return CORD_cat(code, "));");
|
||||
}
|
||||
case Return: {
|
||||
if (!env->fn_ctx) code_err(ast, "This return statement is not inside any function");
|
||||
auto ret = Match(ast, Return)->value;
|
||||
@ -2023,7 +2041,7 @@ CORD compile(env_t *env, ast_t *ast)
|
||||
case Extern: code_err(ast, "Externs are not supported as expressions");
|
||||
case TableEntry: code_err(ast, "Table entries should not be compiled directly");
|
||||
case Declare: case Assign: case UpdateAssign: case For: case While: case StructDef: case LangDef:
|
||||
case EnumDef: case FunctionDef: case Skip: case Stop: case Pass: case Return: case DocTest:
|
||||
case EnumDef: case FunctionDef: case Skip: case Stop: case Pass: case Return: case DocTest: case PrintStatement:
|
||||
code_err(ast, "This is not a valid expression");
|
||||
case Unknown: code_err(ast, "Unknown AST");
|
||||
}
|
||||
|
53
parse.c
53
parse.c
@ -97,6 +97,7 @@ static PARSER(parse_extern);
|
||||
static PARSER(parse_inline_c);
|
||||
static PARSER(parse_declaration);
|
||||
static PARSER(parse_doctest);
|
||||
static PARSER(parse_say);
|
||||
static PARSER(parse_use);
|
||||
static PARSER(parse_import);
|
||||
static PARSER(parse_linker);
|
||||
@ -1527,7 +1528,8 @@ PARSER(parse_assignment) {
|
||||
PARSER(parse_statement) {
|
||||
ast_t *stmt = NULL;
|
||||
if ((stmt=parse_declaration(ctx, pos))
|
||||
|| (stmt=parse_doctest(ctx, pos)))
|
||||
|| (stmt=parse_doctest(ctx, pos))
|
||||
|| (stmt=parse_say(ctx, pos)))
|
||||
return stmt;
|
||||
|
||||
if (!(false
|
||||
@ -2014,6 +2016,55 @@ PARSER(parse_doctest) {
|
||||
return NewAST(ctx->file, start, pos, DocTest, .expr=expr, .output=output);
|
||||
}
|
||||
|
||||
PARSER(parse_say) {
|
||||
const char *start = pos;
|
||||
if (!match(&pos, "!!")) return NULL;
|
||||
spaces(&pos);
|
||||
|
||||
ast_list_t *chunks = NULL;
|
||||
CORD chunk = CORD_EMPTY;
|
||||
const char *chunk_start = pos;
|
||||
const char open_interp = '{', close_interp = '}';
|
||||
while (pos < ctx->file->text + ctx->file->len) {
|
||||
if (*pos == open_interp) { // Interpolation
|
||||
const char *interp_start = pos;
|
||||
if (chunk) {
|
||||
ast_t *literal = NewAST(ctx->file, chunk_start, pos, TextLiteral, .cord=chunk);
|
||||
chunks = new(ast_list_t, .ast=literal, .next=chunks);
|
||||
chunk = NULL;
|
||||
}
|
||||
++pos;
|
||||
ast_t *interp;
|
||||
if (close_interp) {
|
||||
whitespace(&pos);
|
||||
interp = expect(ctx, interp_start, &pos, parse_expr, "I expected an interpolation expression here");
|
||||
whitespace(&pos);
|
||||
expect_closing(ctx, &pos, (char[]){close_interp, 0}, "I was expecting a '%c' to finish this interpolation", close_interp);
|
||||
} else {
|
||||
if (*pos == ' ' || *pos == '\t')
|
||||
parser_err(ctx, pos, pos+1, "Whitespace is not allowed before an interpolation here");
|
||||
interp = expect(ctx, interp_start, &pos, parse_term, "I expected an interpolation term here");
|
||||
}
|
||||
chunks = new(ast_list_t, .ast=interp, .next=chunks);
|
||||
chunk_start = pos;
|
||||
} else if (*pos == '\r' || *pos == '\n') { // Newline
|
||||
break;
|
||||
} else { // Plain character
|
||||
chunk = CORD_cat_char(chunk, *pos);
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
|
||||
if (chunk) {
|
||||
ast_t *literal = NewAST(ctx->file, chunk_start, pos, TextLiteral, .cord=chunk);
|
||||
chunks = new(ast_list_t, .ast=literal, .next=chunks);
|
||||
chunk = NULL;
|
||||
}
|
||||
|
||||
REVERSE_LIST(chunks);
|
||||
return NewAST(ctx->file, start, pos, PrintStatement, .to_print=chunks);
|
||||
}
|
||||
|
||||
PARSER(parse_use) {
|
||||
const char *start = pos;
|
||||
if (!match_word(&pos, "use")) return NULL;
|
||||
|
@ -1,5 +1,7 @@
|
||||
func main():
|
||||
>> str := "Hello Amélie!"
|
||||
!! Testing strings like {str}
|
||||
|
||||
>> str:upper()
|
||||
= "HELLO AMÉLIE!"
|
||||
>> str:lower()
|
||||
@ -7,6 +9,7 @@ func main():
|
||||
>> str:lower():title()
|
||||
= "Hello Amélie!"
|
||||
|
||||
|
||||
>> \UE9
|
||||
= "é"
|
||||
|
||||
|
@ -735,7 +735,7 @@ type_t *get_type(env_t *env, ast_t *ast)
|
||||
case Use: {
|
||||
return Type(ModuleType, Match(ast, Use)->name);
|
||||
}
|
||||
case Return: case Stop: case Skip: {
|
||||
case Return: case Stop: case Skip: case PrintStatement: {
|
||||
return Type(AbortType);
|
||||
}
|
||||
case Pass: return Type(VoidType);
|
||||
|
Loading…
Reference in New Issue
Block a user