aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ast.c1
-rw-r--r--ast.h5
-rw-r--r--compile.c20
-rw-r--r--parse.c53
-rw-r--r--test/text.tm3
-rw-r--r--typecheck.c2
6 files changed, 80 insertions, 4 deletions
diff --git a/ast.c b/ast.c
index 1592ea05..4971b841 100644
--- a/ast.c
+++ b/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))
diff --git a/ast.h b/ast.h
index 64e88610..f58e8595 100644
--- a/ast.h
+++ b/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,
@@ -152,6 +152,9 @@ struct ast_s {
ast_list_t *children;
} TextJoin;
struct {
+ ast_list_t *to_print;
+ } PrintStatement;
+ struct {
ast_t *var;
ast_t *value;
} Declare;
diff --git a/compile.c b/compile.c
index c72c0afc..b42a175b 100644
--- a/compile.c
+++ b/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");
}
diff --git a/parse.c b/parse.c
index 73c65d46..fd757444 100644
--- a/parse.c
+++ b/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;
diff --git a/test/text.tm b/test/text.tm
index edc3b37b..c665d588 100644
--- a/test/text.tm
+++ b/test/text.tm
@@ -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
= "é"
diff --git a/typecheck.c b/typecheck.c
index d21d28ad..8a601c69 100644
--- a/typecheck.c
+++ b/typecheck.c
@@ -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);