Add !! statement for printing text

This commit is contained in:
Bruce Hill 2024-07-04 16:23:05 -04:00
parent d073c10137
commit 9d9fe12987
6 changed files with 80 additions and 4 deletions

1
ast.c
View File

@ -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
View File

@ -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;

View File

@ -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
View File

@ -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;

View File

@ -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
= "é"

View File

@ -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);