new multiline string syntax

This patch also moves a bunch of the parser code into the tokenizer.

Closes #162.
This commit is contained in:
Andrew Kelley 2016-08-01 23:11:31 -07:00
parent 0450b73e3e
commit d0b11af2bd
15 changed files with 810 additions and 1101 deletions

View File

@ -7,27 +7,27 @@ Root = many(TopLevelDecl) "EOF"
TopLevelDecl = many(Directive) option(VisibleMod) (FnDef | ExternDecl | ContainerDecl | GlobalVarDecl | ErrorValueDecl | TypeDecl | UseDecl)
TypeDecl = "type" "Symbol" "=" TypeExpr ";"
TypeDecl = "type" Symbol "=" TypeExpr ";"
ErrorValueDecl = "error" "Symbol" ";"
ErrorValueDecl = "error" Symbol ";"
GlobalVarDecl = VariableDeclaration ";"
VariableDeclaration = ("var" | "const") "Symbol" option(":" TypeExpr) "=" Expression
VariableDeclaration = ("var" | "const") Symbol option(":" TypeExpr) "=" Expression
ContainerDecl = ("struct" | "enum" | "union") "Symbol" option(ParamDeclList) "{" many(StructMember) "}"
ContainerDecl = ("struct" | "enum" | "union") Symbol option(ParamDeclList) "{" many(StructMember) "}"
StructMember = many(Directive) option(VisibleMod) (StructField | FnDef | GlobalVarDecl | ContainerDecl)
StructField = "Symbol" option(":" Expression) ",")
StructField = Symbol option(":" Expression) ",")
UseDecl = "use" Expression ";"
ExternDecl = "extern" (FnProto | VariableDeclaration) ";"
FnProto = "fn" option("Symbol") ParamDeclList option("->" TypeExpr)
FnProto = "fn" option(Symbol) ParamDeclList option("->" TypeExpr)
Directive = "#" "Symbol" "(" Expression ")"
Directive = "#" Symbol "(" Expression ")"
VisibleMod = "pub" | "export"
@ -35,13 +35,13 @@ FnDef = option("inline" | "extern") FnProto Block
ParamDeclList = "(" list(ParamDecl, ",") ")"
ParamDecl = option("noalias" | "inline") option("Symbol" ":") TypeExpr | "..."
ParamDecl = option("noalias" | "inline") option(Symbol ":") TypeExpr | "..."
Block = "{" list(option(Statement), ";") "}"
Statement = Label | VariableDeclaration ";" | Defer ";" | NonBlockExpression ";" | BlockExpression
Label = "Symbol" ":"
Label = Symbol ":"
Expression = BlockExpression | NonBlockExpression
@ -49,23 +49,23 @@ TypeExpr = PrefixOpExpression
NonBlockExpression = ReturnExpression | AssignmentExpression
AsmExpression = "asm" option("volatile") "(" "String" option(AsmOutput) ")"
AsmExpression = "asm" option("volatile") "(" String option(AsmOutput) ")"
AsmOutput = ":" list(AsmOutputItem, ",") option(AsmInput)
AsmInput = ":" list(AsmInputItem, ",") option(AsmClobbers)
AsmOutputItem = "[" "Symbol" "]" "String" "(" ("Symbol" | "->" TypeExpr) ")"
AsmOutputItem = "[" Symbol "]" String "(" (Symbol | "->" TypeExpr) ")"
AsmInputItem = "[" "Symbol" "]" "String" "(" Expression ")"
AsmInputItem = "[" Symbol "]" String "(" Expression ")"
AsmClobbers= ":" list("String", ",")
AsmClobbers= ":" list(String, ",")
UnwrapExpression = BoolOrExpression (UnwrapMaybe | UnwrapError) | BoolOrExpression
UnwrapMaybe = "??" Expression
UnwrapError = "%%" option("|" "Symbol" "|") Expression
UnwrapError = "%%" option("|" Symbol "|") Expression
AssignmentExpression = UnwrapExpression AssignmentOperator UnwrapExpression | UnwrapExpression
@ -75,13 +75,13 @@ BlockExpression = IfExpression | Block | WhileExpression | ForExpression | Switc
SwitchExpression = "switch" "(" Expression ")" "{" many(SwitchProng) "}"
SwitchProng = (list(SwitchItem, ",") | "else") "=>" option("|" "Symbol" "|") Expression ","
SwitchProng = (list(SwitchItem, ",") | "else") "=>" option("|" Symbol "|") Expression ","
SwitchItem = Expression | (Expression "..." Expression)
WhileExpression = "while" "(" Expression option(";" Expression) ")" Expression
ForExpression = "for" "(" Expression ")" option("|" option("*") "Symbol" option("," "Symbol") "|") Expression
ForExpression = "for" "(" Expression ")" option("|" option("*") Symbol option("," Symbol) "|") Expression
BoolOrExpression = BoolAndExpression "||" BoolOrExpression | BoolAndExpression
@ -93,7 +93,7 @@ IfExpression = IfVarExpression | IfBoolExpression
IfBoolExpression = "if" "(" Expression ")" Expression option(Else)
IfVarExpression = "if" "(" ("const" | "var") option("*") "Symbol" option(":" TypeExpr) "?=" Expression ")" Expression Option(Else)
IfVarExpression = "if" "(" ("const" | "var") option("*") Symbol option(":" TypeExpr) "?=" Expression ")" Expression Option(Else)
Else = "else" Expression
@ -127,7 +127,7 @@ PrefixOpExpression = PrefixOp PrefixOpExpression | SuffixOpExpression
SuffixOpExpression = PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
FieldAccessExpression = "." "Symbol"
FieldAccessExpression = "." Symbol
FnCallExpression = "(" list(Expression, ",") ")"
@ -139,15 +139,15 @@ ContainerInitExpression = "{" ContainerInitBody "}"
ContainerInitBody = list(StructLiteralField, ",") | list(Expression, ",")
StructLiteralField = "." "Symbol" "=" Expression
StructLiteralField = "." Symbol "=" Expression
PrefixOp = "!" | "-" | "~" | "*" | ("&" option("const")) | "?" | "%" | "%%" | "??" | "-%"
PrimaryExpression = "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." "Symbol")
PrimaryExpression = Number | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol)
ArrayType = "[" option(Expression) "]" option("const") TypeExpr
GotoExpression = "goto" "Symbol"
GotoExpression = "goto" Symbol
GroupedExpression = "(" Expression ")"
@ -265,14 +265,13 @@ from codegen.
### Literals
#### Character and String Literals
```
Literal Example Characters Escapes Null Term Type
Byte 'H' All ASCII Byte No u8
UTF-8 Bytes "hello" All Unicode Byte & Unicode No [5]u8
UTF-8 C string c"hello" All Unicode Byte & Unicode Yes &const u8
UTF-8 Raw String r"X(hello)X" All Unicode None No [5]u8
UTF-8 Raw C String rc"X(hello)X" All Unicode None Yes &const u8
```
### Escapes
@ -291,26 +290,56 @@ UTF-8 Raw C String rc"X(hello)X" All Unicode None Yes &const
Note that the maximum valid Unicode point is 0x10ffff.
##### Raw Strings
##### Multiline String Literals
Raw string literals have no escapes and can span across multiple lines. To
start a raw string, use 'r"' or 'rc"' followed by unique bytes followed by '('.
To end a raw string, use ')' followed by the same unique bytes, followed by '"'.
Multiline string literals have no escapes and can span across multiple lines.
To start a multiline string literal, use the `\\` token. Just like a comment,
the string literal goes until the end of the line. The end of the line is not
included in the string literal.
However, if the next line begins with `\\` then a newline is appended and
the string literal continues.
#### Numeric Literals
Example:
```zig
const hello_world_in_c =
\\#include <stdio.h>
\\
\\int main(int argc, char **argv) {
\\ printf("hello world\n");
\\ return 0;
\\}
;
```
Number literals Example Exponentiation
Decimal integer 98222 N/A
Hex integer 0xff N/A
Octal integer 0o77 N/A
Binary integer 0b11110000 N/A
Floating-point 123.0E+77 Optional
Hex floating point TODO TODO
For a multiline C string literal, prepend `c` to each `\\`. Example:
```zig
const c_string_literal =
c\\#include <stdio.h>
c\\
c\\int main(int argc, char **argv) {
c\\ printf("hello world\n");
c\\ return 0;
c\\}
;
```
In this example the variable `c_string_literal` has type `&const char` and
has a terminating null byte.
#### Number Literals
Number literals | Example | Exponentiation
--------------------|-------------|--------------
Decimal integer | 98222 | N/A
Hex integer | 0xff | N/A
Octal integer | 0o77 | N/A
Binary integer | 0b11110000 | N/A
Floating point | 123.0E+77 | Optional
Hex floating point | 0x103.70p-5 | Optional
### Identifiers
TODO

View File

@ -1,11 +1,12 @@
" Vim syntax file
" Language: Zig
" Maintainer: Andrew Kelley
" Latest Revision: 28 July 2016
" Latest Revision: 03 August 2016
if exists("b:current_syntax")
finish
endif
let b:current_syntax = "zig"
syn keyword zigStorage const var extern export pub noalias inline noinline
syn keyword zigStructure struct enum union
@ -24,33 +25,30 @@ syn keyword zigBoolean true false
syn match zigOperator display "\%(+%\?\|-%\?\|/\|*%\?\|=\|\^\|&\|?\||\|!\|>\|<\|%\|<<%\?\|>>\|&&\|||\)=\?"
syn match zigArrowCharacter display "->"
syn match zigDecNumber display "\<[0-9][0-9_]*\%([iu]\%(size\|8\|16\|32\|64\)\)\="
syn match zigHexNumber display "\<0x[a-fA-F0-9_]\+\%([iu]\%(size\|8\|16\|32\|64\)\)\="
syn match zigOctNumber display "\<0o[0-7_]\+\%([iu]\%(size\|8\|16\|32\|64\)\)\="
syn match zigBinNumber display "\<0b[01_]\+\%([iu]\%(size\|8\|16\|32\|64\)\)\="
syn match zigDecNumber display "\<[0-9]*\%(.[0-9]\+\)\=\%([eE][+-]\?[0-9]\+\)\="
syn match zigHexNumber display "\<0x[a-fA-F0-9]\+\%(.[a-fA-F0-9]\+\%([pP][+-]\?[0-9]\+\)\?\)\="
syn match zigOctNumber display "\<0o[0-7]\+"
syn match zigBinNumber display "\<0b[01]\+\%(.[01]\+\%([eE][+-]\?[0-9]\+\)\?\)\="
syn match zigCharacterInvalid display contained /b\?'\zs[\n\r\t']\ze'/
syn match zigCharacterInvalidUnicode display contained /b'\zs[^[:cntrl:][:graph:][:alnum:][:space:]]\ze'/
syn match zigCharacter /b'\([^\\]\|\\\(.\|x\x\{2}\)\)'/ contains=zigEscape,zigEscapeError,zigCharacterInvalid,zigCharacterInvalidUnicode
syn match zigCharacter /'\([^\\]\|\\\(.\|x\x\{2}\|u\x\{4}\|U\x\{8}\|u{\x\{1,6}}\)\)'/ contains=zigEscape,zigEscapeUnicode,zigEscapeError,zigCharacterInvalid
syn match zigShebang /\%^#![^[].*/
syn match zigCharacter /'\([^\\]\|\\\(.\|x\x\{2}\|u\x\{4}\|U\x\{6}\)\)'/ contains=zigEscape,zigEscapeUnicode,zigEscapeError,zigCharacterInvalid
syn region zigCommentLine start="//" end="$" contains=zigTodo,@Spell
syn region zigCommentLineDoc start="//\%(//\@!\|!\)" end="$" contains=zigTodo,@Spell
" TODO match only the first '\\' within the zigMultilineString as zigMultilineStringPrefix
syn match zigMultilineStringPrefix display contained /c\?\\\\/
syn region zigMultilineString start="c\?\\\\" end="$" contains=zigMultilineStringPrefix
syn keyword zigTodo contained TODO XXX
syn match zigEscapeError display contained /\\./
syn match zigEscape display contained /\\\([nrt0\\'"]\|x\x\{2}\)/
syn match zigEscapeUnicode display contained /\\\(u\x\{4}\|U\x\{8}\)/
syn match zigEscapeUnicode display contained /\\u{\x\{1,6}}/
syn match zigStringContinuation display contained /\\\n\s*/
syn region zigString start=+c\?"+ skip=+\\\\\|\\"+ end=+"+ oneline contains=zigEscape,zigEscapeUnicode,zigEscapeError,zigStringContinuation,@Spell
syn region zigString start='r"\z([^)]*\)(' end=')\z1"' contains=@Spell
let b:current_syntax = "zig"
syn match zigEscape display contained /\\\([nrt\\'"]\|x\x\{2}\)/
syn match zigEscapeUnicode display contained /\\\(u\x\{4}\|U\x\{6}\)/
syn region zigString start=+c\?"+ skip=+\\\\\|\\"+ end=+"+ oneline contains=zigEscape,zigEscapeUnicode,zigEscapeError,@Spell
hi def link zigDecNumber zigNumber
hi def link zigHexNumber zigNumber
@ -59,12 +57,12 @@ hi def link zigBinNumber zigNumber
hi def link zigKeyword Keyword
hi def link zigType Type
hi def link zigShebang Comment
hi def link zigCommentLine Comment
hi def link zigCommentLineDoc SpecialComment
hi def link zigTodo Todo
hi def link zigStringContinuation Special
hi def link zigString String
hi def link zigMultilineString String
hi def link zigMultilineStringPrefix Comment
hi def link zigCharacterInvalid Error
hi def link zigCharacterInvalidUnicode zigCharacterInvalid
hi def link zigCharacter Character

View File

@ -194,7 +194,7 @@ struct AstNodeRoot {
struct AstNodeFnProto {
TopLevelDecl top_level_decl;
Buf name;
Buf *name;
ZigList<AstNode *> params;
AstNode *return_type;
bool is_var_args;
@ -229,7 +229,7 @@ struct AstNodeFnDecl {
};
struct AstNodeParamDecl {
Buf name;
Buf *name;
AstNode *type;
bool is_noalias;
bool is_inline;
@ -279,7 +279,7 @@ struct AstNodeDefer {
struct AstNodeVariableDeclaration {
TopLevelDecl top_level_decl;
Buf symbol;
Buf *symbol;
bool is_const;
bool is_extern;
// one or both of type and expr will be non null
@ -293,7 +293,7 @@ struct AstNodeVariableDeclaration {
struct AstNodeTypeDecl {
TopLevelDecl top_level_decl;
Buf symbol;
Buf *symbol;
AstNode *child_type;
// populated by semantic analyzer
@ -305,7 +305,7 @@ struct AstNodeTypeDecl {
struct AstNodeErrorValueDecl {
TopLevelDecl top_level_decl;
Buf name;
Buf *name;
// populated by semantic analyzer
ErrorTableEntry *err;
@ -434,7 +434,7 @@ struct AstNodeSliceExpr {
struct AstNodeFieldAccessExpr {
AstNode *struct_expr;
Buf field_name;
Buf *field_name;
// populated by semantic analyzer
TypeStructField *type_struct_field;
@ -448,7 +448,7 @@ struct AstNodeFieldAccessExpr {
};
struct AstNodeDirective {
Buf name;
Buf *name;
AstNode *expr;
};
@ -555,7 +555,7 @@ struct AstNodeSwitchRange {
};
struct AstNodeLabel {
Buf name;
Buf *name;
// populated by semantic analyzer
Expr resolved_expr;
@ -563,7 +563,7 @@ struct AstNodeLabel {
};
struct AstNodeGoto {
Buf name;
Buf *name;
// populated by semantic analyzer
Expr resolved_expr;
@ -571,9 +571,9 @@ struct AstNodeGoto {
};
struct AsmOutput {
Buf asm_symbolic_name;
Buf constraint;
Buf variable_name;
Buf *asm_symbolic_name;
Buf *constraint;
Buf *variable_name;
AstNode *return_type; // null unless "=r" and return
// populated by semantic analyzer
@ -581,8 +581,8 @@ struct AsmOutput {
};
struct AsmInput {
Buf asm_symbolic_name;
Buf constraint;
Buf *asm_symbolic_name;
Buf *constraint;
AstNode *expr;
};
@ -593,8 +593,7 @@ struct SrcPos {
struct AstNodeAsmExpr {
bool is_volatile;
Buf asm_template;
ZigList<SrcPos> offset_map;
Buf *asm_template;
ZigList<AsmToken> token_list;
ZigList<AsmOutput*> output_list;
ZigList<AsmInput*> input_list;
@ -613,7 +612,7 @@ enum ContainerKind {
struct AstNodeStructDecl {
TopLevelDecl top_level_decl;
Buf name;
Buf *name;
ContainerKind kind;
ZigList<AstNode *> generic_params;
bool generic_params_is_var_args; // always an error but it can happen from parsing
@ -629,12 +628,12 @@ struct AstNodeStructDecl {
struct AstNodeStructField {
TopLevelDecl top_level_decl;
Buf name;
Buf *name;
AstNode *type;
};
struct AstNodeStringLiteral {
Buf buf;
Buf *buf;
bool c;
// populated by semantic analyzer:
@ -648,29 +647,19 @@ struct AstNodeCharLiteral {
Expr resolved_expr;
};
enum NumLit {
NumLitFloat,
NumLitUInt,
};
struct AstNodeNumberLiteral {
NumLit kind;
BigNum *bignum;
// overflow is true if when parsing the number, we discovered it would not
// fit without losing data in a uint64_t or double
bool overflow;
union {
uint64_t x_uint;
double x_float;
} data;
// populated by semantic analyzer
Expr resolved_expr;
};
struct AstNodeStructValueField {
Buf name;
Buf *name;
AstNode *expr;
// populated by semantic analyzer
@ -706,7 +695,7 @@ struct AstNodeUndefinedLiteral {
};
struct AstNodeSymbolExpr {
Buf symbol;
Buf *symbol;
// populated by semantic analyzer
Expr resolved_expr;

View File

@ -1053,7 +1053,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
if (fn_proto->top_level_decl.directives) {
for (int i = 0; i < fn_proto->top_level_decl.directives->length; i += 1) {
AstNode *directive_node = fn_proto->top_level_decl.directives->at(i);
Buf *name = &directive_node->data.directive.name;
Buf *name = directive_node->data.directive.name;
if (buf_eql_str(name, "attribute")) {
if (fn_table_entry->fn_def_node) {
@ -1251,7 +1251,7 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt
for (uint32_t i = 0; i < field_count; i += 1) {
AstNode *field_node = decl_node->data.struct_decl.fields.at(i);
TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i];
type_enum_field->name = &field_node->data.struct_field.name;
type_enum_field->name = field_node->data.struct_field.name;
TypeTableEntry *field_type = analyze_type_expr(g, import, context,
field_node->data.struct_field.type);
type_enum_field->type_entry = field_type;
@ -1365,7 +1365,7 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt
uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, enum_type->type_ref);
LLVMZigDIType *replacement_di_type = LLVMZigCreateDebugStructType(g->dbuilder,
LLVMZigFileToScope(import->di_file),
buf_ptr(&decl_node->data.struct_decl.name),
buf_ptr(decl_node->data.struct_decl.name),
import->di_file, decl_node->line + 1,
debug_size_in_bits,
debug_align_in_bits,
@ -1381,7 +1381,7 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt
uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref);
uint64_t tag_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, tag_type_entry->type_ref);
LLVMZigDIType *tag_di_type = LLVMZigCreateDebugEnumerationType(g->dbuilder,
LLVMZigFileToScope(import->di_file), buf_ptr(&decl_node->data.struct_decl.name),
LLVMZigFileToScope(import->di_file), buf_ptr(decl_node->data.struct_decl.name),
import->di_file, decl_node->line + 1,
tag_debug_size_in_bits,
tag_debug_align_in_bits,
@ -1441,7 +1441,7 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE
for (int i = 0; i < field_count; i += 1) {
AstNode *field_node = decl_node->data.struct_decl.fields.at(i);
TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
type_struct_field->name = &field_node->data.struct_field.name;
type_struct_field->name = field_node->data.struct_field.name;
TypeTableEntry *field_type = analyze_type_expr(g, import, context,
field_node->data.struct_field.type);
type_struct_field->type_entry = field_type;
@ -1514,7 +1514,7 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE
uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, struct_type->type_ref);
LLVMZigDIType *replacement_di_type = LLVMZigCreateDebugStructType(g->dbuilder,
LLVMZigFileToScope(import->di_file),
buf_ptr(&decl_node->data.struct_decl.name),
buf_ptr(decl_node->data.struct_decl.name),
import->di_file, decl_node->line + 1,
debug_size_in_bits,
debug_align_in_bits,
@ -1570,7 +1570,7 @@ static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstN
assert(!is_generic_instance || !is_generic_fn);
AstNode *parent_decl = proto_node->data.fn_proto.top_level_decl.parent_decl;
Buf *proto_name = &proto_node->data.fn_proto.name;
Buf *proto_name = proto_node->data.fn_proto.name;
AstNode *fn_def_node = proto_node->data.fn_proto.fn_def_node;
bool is_extern = proto_node->data.fn_proto.is_extern;
@ -1645,7 +1645,7 @@ static void scan_struct_decl(CodeGen *g, ImportTableEntry *import, BlockContext
return;
}
Buf *name = &node->data.struct_decl.name;
Buf *name = node->data.struct_decl.name;
TypeTableEntry *container_type = get_partial_container_type(g, import, context,
node->data.struct_decl.kind, node, buf_ptr(name));
node->data.struct_decl.type_entry = container_type;
@ -1692,7 +1692,7 @@ static void preview_error_value_decl(CodeGen *g, AstNode *node) {
ErrorTableEntry *err = allocate<ErrorTableEntry>(1);
err->decl_node = node;
buf_init_from_buf(&err->name, &node->data.error_value_decl.name);
buf_init_from_buf(&err->name, node->data.error_value_decl.name);
auto existing_entry = g->error_table.maybe_get(&err->name);
if (existing_entry) {
@ -1749,7 +1749,7 @@ static void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only)
case NodeTypeTypeDecl:
{
AstNode *type_node = node->data.type_decl.child_type;
Buf *decl_name = &node->data.type_decl.symbol;
Buf *decl_name = node->data.type_decl.symbol;
TypeTableEntry *entry;
if (node->data.type_decl.override_type) {
@ -2479,12 +2479,12 @@ static TypeTableEntry *analyze_container_init_expr(CodeGen *g, ImportTableEntry
val_field_node->block_context = context;
TypeStructField *type_field = find_struct_type_field(container_type,
&val_field_node->data.struct_val_field.name);
val_field_node->data.struct_val_field.name);
if (!type_field) {
add_node_error(g, val_field_node,
buf_sprintf("no member named '%s' in '%s'",
buf_ptr(&val_field_node->data.struct_val_field.name), buf_ptr(&container_type->name)));
buf_ptr(val_field_node->data.struct_val_field.name), buf_ptr(&container_type->name)));
continue;
}
@ -2604,7 +2604,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
AstNode **struct_expr_node = &node->data.field_access_expr.struct_expr;
TypeTableEntry *struct_type = analyze_expression(g, import, context, nullptr, *struct_expr_node);
Buf *field_name = &node->data.field_access_expr.field_name;
Buf *field_name = node->data.field_access_expr.field_name;
bool wrapped_in_fn_call = node->data.field_access_expr.is_fn_call;
@ -2965,6 +2965,22 @@ static TypeTableEntry *resolve_expr_const_val_as_string_lit(CodeGen *g, AstNode
return get_array_type(g, g->builtin_types.entry_u8, buf_len(str));
}
static TypeTableEntry *resolve_expr_const_val_as_bignum(CodeGen *g, AstNode *node,
TypeTableEntry *expected_type, BigNum *bignum, bool depends_on_compile_var)
{
Expr *expr = get_resolved_expr(node);
expr->const_val.ok = true;
expr->const_val.depends_on_compile_var = depends_on_compile_var;
bignum_init_bignum(&expr->const_val.data.x_bignum, bignum);
if (bignum->kind == BigNumKindInt) {
return g->builtin_types.entry_num_lit_int;
} else if (bignum->kind == BigNumKindFloat) {
return g->builtin_types.entry_num_lit_float;
} else {
zig_unreachable();
}
}
static TypeTableEntry *resolve_expr_const_val_as_unsigned_num_lit(CodeGen *g, AstNode *node,
TypeTableEntry *expected_type, uint64_t x, bool depends_on_compile_var)
@ -2978,17 +2994,6 @@ static TypeTableEntry *resolve_expr_const_val_as_unsigned_num_lit(CodeGen *g, As
return g->builtin_types.entry_num_lit_int;
}
static TypeTableEntry *resolve_expr_const_val_as_float_num_lit(CodeGen *g, AstNode *node,
TypeTableEntry *expected_type, double x)
{
Expr *expr = get_resolved_expr(node);
expr->const_val.ok = true;
bignum_init_float(&expr->const_val.data.x_bignum, x);
return g->builtin_types.entry_num_lit_float;
}
static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *import,
BlockContext *context, AstNode *node, Buf *err_name)
{
@ -3073,7 +3078,7 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import,
return resolve_expr_const_val_as_type(g, node, node->data.symbol_expr.override_type_entry, false);
}
Buf *variable_name = &node->data.symbol_expr.symbol;
Buf *variable_name = node->data.symbol_expr.symbol;
auto primitive_table_entry = g->primitive_type_table.maybe_get(variable_name);
if (primitive_table_entry) {
@ -3177,7 +3182,7 @@ static TypeTableEntry *analyze_lvalue(CodeGen *g, ImportTableEntry *import, Bloc
return g->builtin_types.entry_invalid;
}
if (purpose != LValPurposeAddressOf) {
Buf *name = &lhs_node->data.symbol_expr.symbol;
Buf *name = lhs_node->data.symbol_expr.symbol;
VariableTableEntry *var = find_variable(g, block_context, name);
if (var) {
if (var->is_const) {
@ -3742,7 +3747,7 @@ static TypeTableEntry *analyze_unwrap_error_expr(CodeGen *g, ImportTableEntry *i
if (var_node) {
child_context = new_block_context(node, parent_context);
var_node->block_context = child_context;
Buf *var_name = &var_node->data.symbol_expr.symbol;
Buf *var_name = var_node->data.symbol_expr.symbol;
node->data.unwrap_err_expr.var = add_local_var(g, var_node, import, child_context, var_name,
g->builtin_types.entry_pure_error, true, nullptr);
} else {
@ -3827,7 +3832,7 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa
assert(type != nullptr); // should have been caught by the parser
VariableTableEntry *var = add_local_var(g, source_node, import, context,
&variable_declaration->symbol, type, is_const,
variable_declaration->symbol, type, is_const,
expr_is_maybe ? nullptr : variable_declaration->expr);
variable_declaration->variable = var;
@ -3886,15 +3891,7 @@ static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry
return g->builtin_types.entry_invalid;
}
if (node->data.number_literal.kind == NumLitUInt) {
return resolve_expr_const_val_as_unsigned_num_lit(g, node,
expected_type, node->data.number_literal.data.x_uint, false);
} else if (node->data.number_literal.kind == NumLitFloat) {
return resolve_expr_const_val_as_float_num_lit(g, node,
expected_type, node->data.number_literal.data.x_float);
} else {
zig_unreachable();
}
return resolve_expr_const_val_as_bignum(g, node, expected_type, node->data.number_literal.bignum, false);
}
static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import, BlockContext *context,
@ -4034,13 +4031,13 @@ static TypeTableEntry *analyze_for_expr(CodeGen *g, ImportTableEntry *import, Bl
AstNode *elem_var_node = node->data.for_expr.elem_node;
elem_var_node->block_context = child_context;
Buf *elem_var_name = &elem_var_node->data.symbol_expr.symbol;
Buf *elem_var_name = elem_var_node->data.symbol_expr.symbol;
node->data.for_expr.elem_var = add_local_var(g, elem_var_node, import, child_context, elem_var_name,
var_type, true, nullptr);
AstNode *index_var_node = node->data.for_expr.index_node;
if (index_var_node) {
Buf *index_var_name = &index_var_node->data.symbol_expr.symbol;
Buf *index_var_name = index_var_node->data.symbol_expr.symbol;
index_var_node->block_context = child_context;
node->data.for_expr.index_var = add_local_var(g, index_var_node, import, child_context, index_var_name,
g->builtin_types.entry_usize, true, nullptr);
@ -4952,7 +4949,7 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
assert(node->type == NodeTypeFnCallExpr);
AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
Buf *name = &fn_ref_expr->data.symbol_expr.symbol;
Buf *name = fn_ref_expr->data.symbol_expr.symbol;
auto entry = g->builtin_fn_table.maybe_get(name);
@ -5476,7 +5473,7 @@ static TypeTableEntry *analyze_fn_call_with_inline_args(CodeGen *g, ImportTableE
ConstExprValue *const_val = &get_resolved_expr(*param_node)->const_val;
if (const_val->ok) {
VariableTableEntry *var = add_local_var(g, generic_param_decl_node, decl_node->owner, child_context,
&generic_param_decl_node->data.param_decl.name, param_type, true, *param_node);
generic_param_decl_node->data.param_decl.name, param_type, true, *param_node);
// This generic function instance could be called with anything, so when this variable is read it
// needs to know that it depends on compile time variable data.
var->force_depends_on_compile_var = true;
@ -5570,7 +5567,7 @@ static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *imp
ConstExprValue *const_val = &get_resolved_expr(*param_node)->const_val;
if (const_val->ok) {
VariableTableEntry *var = add_local_var(g, generic_param_decl_node, decl_node->owner, child_context,
&generic_param_decl_node->data.param_decl.name, param_type, true, *param_node);
generic_param_decl_node->data.param_decl.name, param_type, true, *param_node);
var->force_depends_on_compile_var = true;
} else {
add_node_error(g, *param_node, buf_sprintf("unable to evaluate constant expression"));
@ -5964,7 +5961,7 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,
if (expr_type->id == TypeTableEntryIdEnum) {
if (item_node->type == NodeTypeSymbol) {
Buf *field_name = &item_node->data.symbol_expr.symbol;
Buf *field_name = item_node->data.symbol_expr.symbol;
TypeEnumField *type_enum_field = get_enum_field(expr_type, field_name);
if (type_enum_field) {
item_node->data.symbol_expr.enum_field = type_enum_field;
@ -6000,7 +5997,7 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,
}
} else if (expr_type->id == TypeTableEntryIdErrorUnion) {
if (item_node->type == NodeTypeSymbol) {
Buf *err_name = &item_node->data.symbol_expr.symbol;
Buf *err_name = item_node->data.symbol_expr.symbol;
bool is_ok_case = buf_eql_str(err_name, "Ok");
auto err_table_entry = is_ok_case ? nullptr: g->error_table.maybe_get(err_name);
if (is_ok_case || err_table_entry) {
@ -6072,7 +6069,7 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,
AstNode *var_node = prong_node->data.switch_prong.var_symbol;
if (var_node) {
assert(var_node->type == NodeTypeSymbol);
Buf *var_name = &var_node->data.symbol_expr.symbol;
Buf *var_name = var_node->data.symbol_expr.symbol;
var_node->block_context = child_context;
prong_node->data.switch_prong.var = add_local_var(g, var_node, import,
child_context, var_name, var_type, true, nullptr);
@ -6228,9 +6225,9 @@ static TypeTableEntry *analyze_string_literal_expr(CodeGen *g, ImportTableEntry
TypeTableEntry *expected_type, AstNode *node)
{
if (node->data.string_literal.c) {
return resolve_expr_const_val_as_c_string_lit(g, node, &node->data.string_literal.buf);
return resolve_expr_const_val_as_c_string_lit(g, node, node->data.string_literal.buf);
} else {
return resolve_expr_const_val_as_string_lit(g, node, &node->data.string_literal.buf);
return resolve_expr_const_val_as_string_lit(g, node, node->data.string_literal.buf);
}
}
@ -6255,7 +6252,7 @@ static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import,
child->data.label.label_entry = label;
fn_table_entry->all_labels.append(label);
child_context->label_table.put(&child->data.label.name, label);
child_context->label_table.put(child->data.label.name, label);
return_type = g->builtin_types.entry_void;
continue;
@ -6316,7 +6313,7 @@ static TypeTableEntry *analyze_asm_expr(CodeGen *g, ImportTableEntry *import, Bl
break;
}
} else {
Buf *variable_name = &asm_output->variable_name;
Buf *variable_name = asm_output->variable_name;
VariableTableEntry *var = find_variable(g, context, variable_name);
if (var) {
asm_output->variable = var;
@ -6351,7 +6348,7 @@ static TypeTableEntry *analyze_goto_pass1(CodeGen *g, ImportTableEntry *import,
static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *node) {
assert(node->type == NodeTypeGoto);
Buf *label_name = &node->data.goto_expr.name;
Buf *label_name = node->data.goto_expr.name;
BlockContext *context = node->block_context;
assert(context);
LabelTableEntry *label = find_label(g, context, label_name);
@ -6549,11 +6546,11 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
buf_sprintf("byvalue struct parameters not yet supported on extern functions"));
}
if (buf_len(&param_decl->name) == 0) {
if (buf_len(param_decl->name) == 0) {
add_node_error(g, param_decl_node, buf_sprintf("missing parameter name"));
}
VariableTableEntry *var = add_local_var(g, param_decl_node, import, context, &param_decl->name,
VariableTableEntry *var = add_local_var(g, param_decl_node, import, context, param_decl->name,
type, true, nullptr);
var->src_arg_index = i;
param_decl_node->data.param_decl.variable = var;
@ -6583,7 +6580,7 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
if (!label->used) {
add_node_error(g, label->decl_node,
buf_sprintf("label '%s' defined but not used",
buf_ptr(&label->decl_node->data.label.name)));
buf_ptr(label->decl_node->data.label.name)));
}
}
@ -6640,7 +6637,7 @@ static void scan_decls(CodeGen *g, ImportTableEntry *import, BlockContext *conte
break;
case NodeTypeContainerDecl:
{
Buf *name = &node->data.struct_decl.name;
Buf *name = node->data.struct_decl.name;
add_top_level_decl(g, import, context, node, name);
if (node->data.struct_decl.generic_params.length == 0) {
scan_struct_decl(g, import, context, node);
@ -6653,20 +6650,20 @@ static void scan_decls(CodeGen *g, ImportTableEntry *import, BlockContext *conte
break;
case NodeTypeVariableDeclaration:
{
Buf *name = &node->data.variable_declaration.symbol;
Buf *name = node->data.variable_declaration.symbol;
add_top_level_decl(g, import, context, node, name);
break;
}
case NodeTypeTypeDecl:
{
Buf *name = &node->data.type_decl.symbol;
Buf *name = node->data.type_decl.symbol;
add_top_level_decl(g, import, context, node, name);
break;
}
case NodeTypeFnProto:
{
// if the name is missing, we immediately announce an error
Buf *fn_name = &node->data.fn_proto.name;
Buf *fn_name = node->data.fn_proto.name;
if (buf_len(fn_name) == 0) {
node->data.fn_proto.skip = true;
add_node_error(g, node, buf_sprintf("missing function name"));
@ -6851,6 +6848,9 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package,
assert(import_entry->root);
if (g->verbose) {
ast_print(stderr, import_entry->root, 0);
//fprintf(stderr, "\nReformatted Source:\n");
//fprintf(stderr, "---------------------\n");
//ast_render(stderr, import_entry->root, 4);
}
import_entry->di_file = LLVMZigCreateFile(g->dbuilder, buf_ptr(src_basename), buf_ptr(src_dirname));
@ -6868,7 +6868,7 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package,
if (top_level_decl->type == NodeTypeFnDef) {
AstNode *proto_node = top_level_decl->data.fn_def.fn_proto;
assert(proto_node->type == NodeTypeFnProto);
Buf *proto_name = &proto_node->data.fn_proto.name;
Buf *proto_name = proto_node->data.fn_proto.name;
bool is_private = (proto_node->data.fn_proto.top_level_decl.visib_mod == VisibModPrivate);
@ -7064,7 +7064,7 @@ bool is_node_void_expr(AstNode *node) {
{
AstNode *type_node = node->data.container_init_expr.type;
if (type_node->type == NodeTypeSymbol &&
buf_eql_str(&type_node->data.symbol_expr.symbol, "void"))
buf_eql_str(type_node->data.symbol_expr.symbol, "void"))
{
return true;
}

View File

@ -78,6 +78,24 @@ static const char *visib_mod_string(VisibMod mod) {
zig_unreachable();
}
static const char *return_string(ReturnKind kind) {
switch (kind) {
case ReturnKindUnconditional: return "return";
case ReturnKindError: return "%return";
case ReturnKindMaybe: return "?return";
}
zig_unreachable();
}
static const char *defer_string(ReturnKind kind) {
switch (kind) {
case ReturnKindUnconditional: return "defer";
case ReturnKindError: return "%defer";
case ReturnKindMaybe: return "?defer";
}
zig_unreachable();
}
static const char *extern_string(bool is_extern) {
return is_extern ? "extern " : "";
}
@ -243,7 +261,7 @@ static bool is_node_void(AstNode *node) {
if (node->type == NodeTypeSymbol) {
if (node->data.symbol_expr.override_type_entry) {
return node->data.symbol_expr.override_type_entry->id == TypeTableEntryIdVoid;
} else if (buf_eql_str(&node->data.symbol_expr.symbol, "void")) {
} else if (buf_eql_str(node->data.symbol_expr.symbol, "void")) {
return true;
}
}
@ -260,7 +278,12 @@ static bool is_digit(uint8_t c) {
}
static bool is_printable(uint8_t c) {
return is_alpha_under(c) || is_digit(c) || c == ' ';
static const uint8_t printables[] =
" abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.~`!@#$%^&*()_-+=\\{}[];'\"?/<>,";
for (size_t i = 0; i < array_length(printables); i += 1) {
if (c == printables[i]) return true;
}
return false;
}
static void string_literal_escape(Buf *source, Buf *dest) {
@ -353,18 +376,18 @@ static void render_node(AstRender *ar, AstNode *node) {
const char *extern_str = extern_string(node->data.fn_proto.is_extern);
const char *inline_str = inline_string(node->data.fn_proto.is_inline);
fprintf(ar->f, "%s%s%sfn ", pub_str, inline_str, extern_str);
print_symbol(ar, &node->data.fn_proto.name);
print_symbol(ar, node->data.fn_proto.name);
fprintf(ar->f, "(");
int arg_count = node->data.fn_proto.params.length;
bool is_var_args = node->data.fn_proto.is_var_args;
for (int arg_i = 0; arg_i < arg_count; arg_i += 1) {
AstNode *param_decl = node->data.fn_proto.params.at(arg_i);
assert(param_decl->type == NodeTypeParamDecl);
if (buf_len(&param_decl->data.param_decl.name) > 0) {
if (buf_len(param_decl->data.param_decl.name) > 0) {
const char *noalias_str = param_decl->data.param_decl.is_noalias ? "noalias " : "";
const char *inline_str = param_decl->data.param_decl.is_inline ? "inline " : "";
fprintf(ar->f, "%s%s", noalias_str, inline_str);
print_symbol(ar, &param_decl->data.param_decl.name);
print_symbol(ar, param_decl->data.param_decl.name);
fprintf(ar->f, ": ");
}
render_node(ar, param_decl->data.param_decl.type);
@ -417,21 +440,31 @@ static void render_node(AstRender *ar, AstNode *node) {
fprintf(ar->f, "}");
break;
case NodeTypeDirective:
fprintf(ar->f, "#%s(", buf_ptr(&node->data.directive.name));
fprintf(ar->f, "#%s(", buf_ptr(node->data.directive.name));
render_node(ar, node->data.directive.expr);
fprintf(ar->f, ")\n");
break;
case NodeTypeReturnExpr:
zig_panic("TODO");
{
const char *return_str = return_string(node->data.return_expr.kind);
fprintf(ar->f, "%s ", return_str);
render_node(ar, node->data.return_expr.expr);
break;
}
case NodeTypeDefer:
zig_panic("TODO");
{
const char *defer_str = defer_string(node->data.defer.kind);
fprintf(ar->f, "%s ", defer_str);
render_node(ar, node->data.return_expr.expr);
break;
}
case NodeTypeVariableDeclaration:
{
const char *pub_str = visib_mod_string(node->data.variable_declaration.top_level_decl.visib_mod);
const char *extern_str = extern_string(node->data.variable_declaration.is_extern);
const char *const_or_var = const_or_var_string(node->data.variable_declaration.is_const);
fprintf(ar->f, "%s%s%s ", pub_str, extern_str, const_or_var);
print_symbol(ar, &node->data.variable_declaration.symbol);
print_symbol(ar, node->data.variable_declaration.symbol);
if (node->data.variable_declaration.type) {
fprintf(ar->f, ": ");
@ -446,7 +479,7 @@ static void render_node(AstRender *ar, AstNode *node) {
case NodeTypeTypeDecl:
{
const char *pub_str = visib_mod_string(node->data.type_decl.top_level_decl.visib_mod);
const char *var_name = buf_ptr(&node->data.type_decl.symbol);
const char *var_name = buf_ptr(node->data.type_decl.symbol);
fprintf(ar->f, "%stype %s = ", pub_str, var_name);
render_node(ar, node->data.type_decl.child_type);
break;
@ -463,12 +496,15 @@ static void render_node(AstRender *ar, AstNode *node) {
case NodeTypeUnwrapErrorExpr:
zig_panic("TODO");
case NodeTypeNumberLiteral:
switch (node->data.number_literal.kind) {
case NumLitUInt:
fprintf(ar->f, "%" PRIu64, node->data.number_literal.data.x_uint);
switch (node->data.number_literal.bignum->kind) {
case BigNumKindInt:
{
const char *negative_str = node->data.number_literal.bignum->is_negative ? "-" : "";
fprintf(ar->f, "%s%llu", negative_str, node->data.number_literal.bignum->data.x_uint);
}
break;
case NumLitFloat:
fprintf(ar->f, "%f", node->data.number_literal.data.x_float);
case BigNumKindFloat:
fprintf(ar->f, "%f", node->data.number_literal.bignum->data.x_float);
break;
}
break;
@ -478,7 +514,7 @@ static void render_node(AstRender *ar, AstNode *node) {
fprintf(ar->f, "c");
}
Buf tmp_buf = BUF_INIT;
string_literal_escape(&node->data.string_literal.buf, &tmp_buf);
string_literal_escape(node->data.string_literal.buf, &tmp_buf);
fprintf(ar->f, "\"%s\"", buf_ptr(&tmp_buf));
}
break;
@ -498,7 +534,7 @@ static void render_node(AstRender *ar, AstNode *node) {
if (override_type) {
fprintf(ar->f, "%s", buf_ptr(&override_type->name));
} else {
fprintf(ar->f, "%s", buf_ptr(&node->data.symbol_expr.symbol));
print_symbol(ar, node->data.symbol_expr.symbol);
}
}
break;
@ -513,10 +549,14 @@ static void render_node(AstRender *ar, AstNode *node) {
case NodeTypeFnCallExpr:
if (node->data.fn_call_expr.is_builtin) {
fprintf(ar->f, "@");
} else {
fprintf(ar->f, "(");
}
render_node(ar, node->data.fn_call_expr.fn_ref_expr);
if (!node->data.fn_call_expr.is_builtin) {
fprintf(ar->f, ")");
}
fprintf(ar->f, "(");
render_node(ar, node->data.fn_call_expr.fn_ref_expr);
fprintf(ar->f, ")(");
for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) {
AstNode *param = node->data.fn_call_expr.params.at(i);
if (i != 0) {
@ -537,7 +577,7 @@ static void render_node(AstRender *ar, AstNode *node) {
case NodeTypeFieldAccessExpr:
{
AstNode *lhs = node->data.field_access_expr.struct_expr;
Buf *rhs = &node->data.field_access_expr.field_name;
Buf *rhs = node->data.field_access_expr.field_name;
render_node(ar, lhs);
fprintf(ar->f, ".");
print_symbol(ar, rhs);
@ -577,7 +617,7 @@ static void render_node(AstRender *ar, AstNode *node) {
zig_panic("TODO");
case NodeTypeContainerDecl:
{
const char *struct_name = buf_ptr(&node->data.struct_decl.name);
const char *struct_name = buf_ptr(node->data.struct_decl.name);
const char *pub_str = visib_mod_string(node->data.struct_decl.top_level_decl.visib_mod);
const char *container_str = container_string(node->data.struct_decl.kind);
fprintf(ar->f, "%s%s %s {\n", pub_str, container_str, struct_name);
@ -586,7 +626,7 @@ static void render_node(AstRender *ar, AstNode *node) {
AstNode *field_node = node->data.struct_decl.fields.at(field_i);
assert(field_node->type == NodeTypeStructField);
print_indent(ar);
print_symbol(ar, &field_node->data.struct_field.name);
print_symbol(ar, field_node->data.struct_field.name);
if (!is_node_void(field_node->data.struct_field.type)) {
fprintf(ar->f, ": ");
render_node(ar, field_node->data.struct_field.type);

View File

@ -6,6 +6,7 @@
*/
#include "bignum.hpp"
#include "buffer.hpp"
#include <assert.h>
#include <math.h>
@ -41,6 +42,10 @@ void bignum_init_signed(BigNum *dest, int64_t x) {
}
}
void bignum_init_bignum(BigNum *dest, BigNum *src) {
memcpy(dest, src, sizeof(BigNum));
}
bool bignum_fits_in_bits(BigNum *bn, int bit_count, bool is_signed) {
assert(bn->kind == BigNumKindInt);
@ -343,3 +348,15 @@ bool bignum_cmp_gte(BigNum *op1, BigNum *op2) {
return true;
}
}
bool bignum_increment_by_scalar(BigNum *bignum, uint64_t scalar) {
assert(bignum->kind == BigNumKindInt);
assert(!bignum->is_negative);
return __builtin_uaddll_overflow(bignum->data.x_uint, scalar, &bignum->data.x_uint);
}
bool bignum_multiply_by_scalar(BigNum *bignum, uint64_t scalar) {
assert(bignum->kind == BigNumKindInt);
assert(!bignum->is_negative);
return __builtin_umulll_overflow(bignum->data.x_uint, scalar, &bignum->data.x_uint);
}

View File

@ -5,7 +5,8 @@
* See http://opensource.org/licenses/MIT
*/
#include "buffer.hpp"
#ifndef ZIG_BIGNUM_HPP
#define ZIG_BIGNUM_HPP
#include <stdint.h>
@ -26,6 +27,7 @@ struct BigNum {
void bignum_init_float(BigNum *dest, double x);
void bignum_init_unsigned(BigNum *dest, uint64_t x);
void bignum_init_signed(BigNum *dest, int64_t x);
void bignum_init_bignum(BigNum *dest, BigNum *src);
bool bignum_fits_in_bits(BigNum *bn, int bit_count, bool is_signed);
uint64_t bignum_to_twos_complement(BigNum *bn);
@ -57,4 +59,11 @@ bool bignum_cmp_gt(BigNum *op1, BigNum *op2);
bool bignum_cmp_lte(BigNum *op1, BigNum *op2);
bool bignum_cmp_gte(BigNum *op1, BigNum *op2);
// helper functions
bool bignum_increment_by_scalar(BigNum *bignum, uint64_t scalar);
bool bignum_multiply_by_scalar(BigNum *bignum, uint64_t scalar);
struct Buf;
Buf *bignum_to_buf(BigNum *bn);
#endif

View File

@ -1431,7 +1431,7 @@ static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lva
TypeTableEntry *struct_type = get_expr_type(struct_expr);
if (struct_type->id == TypeTableEntryIdArray) {
Buf *name = &node->data.field_access_expr.field_name;
Buf *name = node->data.field_access_expr.field_name;
assert(buf_eql_str(name, "len"));
return LLVMConstInt(g->builtin_types.entry_usize->type_ref,
struct_type->data.array.len, false);
@ -2726,18 +2726,18 @@ static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *i
}
static int find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok) {
const char *ptr = buf_ptr(&node->data.asm_expr.asm_template) + tok->start + 2;
const char *ptr = buf_ptr(node->data.asm_expr.asm_template) + tok->start + 2;
int len = tok->end - tok->start - 2;
int result = 0;
for (int i = 0; i < node->data.asm_expr.output_list.length; i += 1, result += 1) {
AsmOutput *asm_output = node->data.asm_expr.output_list.at(i);
if (buf_eql_mem(&asm_output->asm_symbolic_name, ptr, len)) {
if (buf_eql_mem(asm_output->asm_symbolic_name, ptr, len)) {
return result;
}
}
for (int i = 0; i < node->data.asm_expr.input_list.length; i += 1, result += 1) {
AsmInput *asm_input = node->data.asm_expr.input_list.at(i);
if (buf_eql_mem(&asm_input->asm_symbolic_name, ptr, len)) {
if (buf_eql_mem(asm_input->asm_symbolic_name, ptr, len)) {
return result;
}
}
@ -2749,7 +2749,7 @@ static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) {
AstNodeAsmExpr *asm_expr = &node->data.asm_expr;
Buf *src_template = &asm_expr->asm_template;
Buf *src_template = asm_expr->asm_template;
Buf llvm_template = BUF_INIT;
buf_resize(&llvm_template, 0);
@ -2796,11 +2796,11 @@ static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) {
for (int i = 0; i < asm_expr->output_list.length; i += 1, total_index += 1) {
AsmOutput *asm_output = asm_expr->output_list.at(i);
bool is_return = (asm_output->return_type != nullptr);
assert(*buf_ptr(&asm_output->constraint) == '=');
assert(*buf_ptr(asm_output->constraint) == '=');
if (is_return) {
buf_appendf(&constraint_buf, "=%s", buf_ptr(&asm_output->constraint) + 1);
buf_appendf(&constraint_buf, "=%s", buf_ptr(asm_output->constraint) + 1);
} else {
buf_appendf(&constraint_buf, "=*%s", buf_ptr(&asm_output->constraint) + 1);
buf_appendf(&constraint_buf, "=*%s", buf_ptr(asm_output->constraint) + 1);
}
if (total_index + 1 < total_constraint_count) {
buf_append_char(&constraint_buf, ',');
@ -2816,7 +2816,7 @@ static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) {
}
for (int i = 0; i < asm_expr->input_list.length; i += 1, total_index += 1, param_index += 1) {
AsmInput *asm_input = asm_expr->input_list.at(i);
buf_append_buf(&constraint_buf, &asm_input->constraint);
buf_append_buf(&constraint_buf, asm_input->constraint);
if (total_index + 1 < total_constraint_count) {
buf_append_char(&constraint_buf, ',');
}
@ -2885,7 +2885,7 @@ static LLVMValueRef gen_container_init_expr(CodeGen *g, AstNode *node) {
if (type_struct_field->type_entry->id == TypeTableEntryIdVoid) {
continue;
}
assert(buf_eql_buf(type_struct_field->name, &field_node->data.struct_val_field.name));
assert(buf_eql_buf(type_struct_field->name, field_node->data.struct_val_field.name));
set_debug_source_node(g, field_node);
LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, type_struct_field->gen_index, "");
@ -3853,7 +3853,7 @@ static void generate_error_name_table(CodeGen *g) {
for (int i = 1; i < g->error_decls.length; i += 1) {
AstNode *error_decl_node = g->error_decls.at(i);
assert(error_decl_node->type == NodeTypeErrorValueDecl);
Buf *name = &error_decl_node->data.error_value_decl.name;
Buf *name = error_decl_node->data.error_value_decl.name;
LLVMValueRef str_init = LLVMConstString(buf_ptr(name), buf_len(name), true);
LLVMValueRef str_global = LLVMAddGlobal(g->module, LLVMTypeOf(str_init), "");
@ -3882,7 +3882,7 @@ static void build_label_blocks(CodeGen *g, FnTableEntry *fn) {
LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn->fn_value, "entry");
for (int i = 0; i < fn->all_labels.length; i += 1) {
LabelTableEntry *label = fn->all_labels.at(i);
Buf *name = &label->decl_node->data.label.name;
Buf *name = label->decl_node->data.label.name;
label->basic_block = LLVMAppendBasicBlock(fn->fn_value, buf_ptr(name));
}
LLVMPositionBuilderAtEnd(g->builder, entry_block);
@ -4951,7 +4951,7 @@ void codegen_generate_h_file(CodeGen *g) {
buf_appendf(&h_buf, "%s %s %s(",
buf_ptr(export_macro),
buf_ptr(&return_type_c),
buf_ptr(&fn_proto->name));
buf_ptr(fn_proto->name));
Buf param_type_c = BUF_INIT;
if (fn_proto->params.length) {
@ -4961,7 +4961,7 @@ void codegen_generate_h_file(CodeGen *g) {
to_c_type(g, param_type, &param_type_c);
buf_appendf(&h_buf, "%s %s",
buf_ptr(&param_type_c),
buf_ptr(&param_decl_node->data.param_decl.name));
buf_ptr(param_decl_node->data.param_decl.name));
if (param_i < fn_proto->params.length - 1)
buf_appendf(&h_buf, ", ");
}

View File

@ -427,7 +427,7 @@ static EvalVar *find_var(EvalFn *ef, Buf *name) {
static bool eval_symbol_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) {
assert(node->type == NodeTypeSymbol);
Buf *name = &node->data.symbol_expr.symbol;
Buf *name = node->data.symbol_expr.symbol;
EvalVar *var = find_var(ef, name);
assert(var);
@ -924,7 +924,7 @@ static bool eval_field_access_expr(EvalFn *ef, AstNode *node, ConstExprValue *ou
TypeTableEntry *struct_type = get_resolved_expr(struct_expr)->type_entry;
if (struct_type->id == TypeTableEntryIdArray) {
Buf *name = &node->data.field_access_expr.field_name;
Buf *name = node->data.field_access_expr.field_name;
assert(buf_eql_str(name, "len"));
zig_panic("TODO");
} else if (struct_type->id == TypeTableEntryIdStruct || (struct_type->id == TypeTableEntryIdPointer &&
@ -971,7 +971,7 @@ static bool eval_for_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) {
if (eval_expr(ef, array_node, &array_val)) return true;
assert(elem_node->type == NodeTypeSymbol);
Buf *elem_var_name = &elem_node->data.symbol_expr.symbol;
Buf *elem_var_name = elem_node->data.symbol_expr.symbol;
if (node->data.for_expr.elem_is_ptr) {
zig_panic("TODO");
@ -980,7 +980,7 @@ static bool eval_for_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) {
Buf *index_var_name = nullptr;
if (index_node) {
assert(index_node->type == NodeTypeSymbol);
index_var_name = &index_node->data.symbol_expr.symbol;
index_var_name = index_node->data.symbol_expr.symbol;
}
uint64_t it_index = 0;
@ -1164,7 +1164,7 @@ static bool eval_var_decl_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_va
my_scope->vars.add_one();
EvalVar *var = &my_scope->vars.last();
var->name = &node->data.variable_declaration.symbol;
var->name = node->data.variable_declaration.symbol;
if (eval_expr(ef, node->data.variable_declaration.expr, &var->value)) return true;
@ -1178,13 +1178,7 @@ static bool eval_number_literal_expr(EvalFn *ef, AstNode *node, ConstExprValue *
assert(!node->data.number_literal.overflow);
out_val->ok = true;
if (node->data.number_literal.kind == NumLitUInt) {
bignum_init_unsigned(&out_val->data.x_bignum, node->data.number_literal.data.x_uint);
} else if (node->data.number_literal.kind == NumLitFloat) {
bignum_init_float(&out_val->data.x_bignum, node->data.number_literal.data.x_float);
} else {
zig_unreachable();
}
bignum_init_bignum(&out_val->data.x_bignum, node->data.number_literal.bignum);
return false;
}
@ -1339,7 +1333,7 @@ static bool eval_fn_args(EvalFnRoot *efr, FnTableEntry *fn, ConstExprValue *args
root_scope->vars.add_one();
EvalVar *eval_var = &root_scope->vars.last();
eval_var->name = &decl_param_node->data.param_decl.name;
eval_var->name = decl_param_node->data.param_decl.name;
eval_var->value = *src_const_val;
}

View File

@ -104,14 +104,14 @@ static AstNode *create_node(Context *c, NodeType type) {
static AstNode *create_symbol_node(Context *c, const char *type_name) {
AstNode *node = create_node(c, NodeTypeSymbol);
buf_init_from_str(&node->data.symbol_expr.symbol, type_name);
node->data.symbol_expr.symbol = buf_create_from_str(type_name);
return node;
}
static AstNode *create_field_access_node(Context *c, const char *lhs, const char *rhs) {
AstNode *node = create_node(c, NodeTypeFieldAccessExpr);
node->data.field_access_expr.struct_expr = create_symbol_node(c, lhs);
buf_init_from_str(&node->data.field_access_expr.field_name, rhs);
node->data.field_access_expr.field_name = buf_create_from_str(rhs);
normalize_parent_ptrs(node);
return node;
}
@ -120,7 +120,7 @@ static AstNode *create_typed_var_decl_node(Context *c, bool is_const, const char
AstNode *type_node, AstNode *init_node)
{
AstNode *node = create_node(c, NodeTypeVariableDeclaration);
buf_init_from_str(&node->data.variable_declaration.symbol, var_name);
node->data.variable_declaration.symbol = buf_create_from_str(var_name);
node->data.variable_declaration.is_const = is_const;
node->data.variable_declaration.top_level_decl.visib_mod = c->visib_mod;
node->data.variable_declaration.expr = init_node;
@ -146,7 +146,7 @@ static AstNode *create_prefix_node(Context *c, PrefixOp op, AstNode *child_node)
static AstNode *create_struct_field_node(Context *c, const char *name, AstNode *type_node) {
assert(type_node);
AstNode *node = create_node(c, NodeTypeStructField);
buf_init_from_str(&node->data.struct_field.name, name);
node->data.struct_field.name = buf_create_from_str(name);
node->data.struct_field.top_level_decl.visib_mod = VisibModPub;
node->data.struct_field.type = type_node;
@ -157,7 +157,7 @@ static AstNode *create_struct_field_node(Context *c, const char *name, AstNode *
static AstNode *create_param_decl_node(Context *c, const char *name, AstNode *type_node, bool is_noalias) {
assert(type_node);
AstNode *node = create_node(c, NodeTypeParamDecl);
buf_init_from_str(&node->data.param_decl.name, name);
node->data.param_decl.name = buf_create_from_str(name);
node->data.param_decl.type = type_node;
node->data.param_decl.is_noalias = is_noalias;
@ -171,17 +171,18 @@ static AstNode *create_char_lit_node(Context *c, uint8_t value) {
return node;
}
// accepts ownership of buf
static AstNode *create_str_lit_node(Context *c, Buf *buf) {
AstNode *node = create_node(c, NodeTypeStringLiteral);
buf_init_from_buf(&node->data.string_literal.buf, buf);
node->data.string_literal.buf = buf;
node->data.string_literal.c = true;
return node;
}
static AstNode *create_num_lit_float(Context *c, double x) {
AstNode *node = create_node(c, NodeTypeNumberLiteral);
node->data.number_literal.kind = NumLitFloat;
node->data.number_literal.data.x_float = x;
node->data.number_literal.bignum = allocate_nonzero<BigNum>(1);
bignum_init_float(node->data.number_literal.bignum, x);
return node;
}
@ -193,8 +194,8 @@ static AstNode *create_num_lit_float_negative(Context *c, double x, bool negativ
static AstNode *create_num_lit_unsigned(Context *c, uint64_t x) {
AstNode *node = create_node(c, NodeTypeNumberLiteral);
node->data.number_literal.kind = NumLitUInt;
node->data.number_literal.data.x_uint = x;
node->data.number_literal.bignum = allocate_nonzero<BigNum>(1);
bignum_init_unsigned(node->data.number_literal.bignum, x);
return node;
}
@ -221,7 +222,7 @@ static AstNode *create_num_lit_signed(Context *c, int64_t x) {
static AstNode *create_type_decl_node(Context *c, const char *name, AstNode *child_type_node) {
AstNode *node = create_node(c, NodeTypeTypeDecl);
buf_init_from_str(&node->data.type_decl.symbol, name);
node->data.type_decl.symbol = buf_create_from_str(name);
node->data.type_decl.top_level_decl.visib_mod = c->visib_mod;
node->data.type_decl.child_type = child_type_node;
@ -240,7 +241,7 @@ static AstNode *create_fn_proto_node(Context *c, Buf *name, TypeTableEntry *fn_t
AstNode *node = create_node(c, NodeTypeFnProto);
node->data.fn_proto.is_inline = true;
node->data.fn_proto.top_level_decl.visib_mod = c->visib_mod;
buf_init_from_buf(&node->data.fn_proto.name, name);
node->data.fn_proto.name = name;
node->data.fn_proto.return_type = make_type_node(c, fn_type->data.fn.fn_type_id.return_type);
for (int i = 0; i < fn_type->data.fn.fn_type_id.param_count; i += 1) {
@ -273,7 +274,7 @@ static AstNode *create_inline_fn_node(Context *c, Buf *fn_name, Buf *var_name, T
fn_call_node->data.fn_call_expr.fn_ref_expr = unwrap_node;
for (int i = 0; i < fn_type->data.fn.fn_type_id.param_count; i += 1) {
AstNode *decl_node = node->data.fn_def.fn_proto->data.fn_proto.params.at(i);
Buf *param_name = &decl_node->data.param_decl.name;
Buf *param_name = decl_node->data.param_decl.name;
fn_call_node->data.fn_call_expr.params.append(create_symbol_node(c, buf_ptr(param_name)));
}
@ -686,10 +687,9 @@ static TypeTableEntry *resolve_qual_type(Context *c, QualType qt, const Decl *de
}
static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) {
Buf fn_name = BUF_INIT;
buf_init_from_str(&fn_name, decl_name(fn_decl));
Buf *fn_name = buf_create_from_str(decl_name(fn_decl));
if (c->fn_table.maybe_get(&fn_name)) {
if (c->fn_table.maybe_get(fn_name)) {
// we already saw this function
return;
}
@ -697,14 +697,14 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) {
TypeTableEntry *fn_type = resolve_qual_type(c, fn_decl->getType(), fn_decl);
if (fn_type->id == TypeTableEntryIdInvalid) {
emit_warning(c, fn_decl, "ignoring function '%s' - unable to resolve type", buf_ptr(&fn_name));
emit_warning(c, fn_decl, "ignoring function '%s' - unable to resolve type", buf_ptr(fn_name));
return;
}
assert(fn_type->id == TypeTableEntryIdFn);
AstNode *node = create_node(c, NodeTypeFnProto);
buf_init_from_buf(&node->data.fn_proto.name, &fn_name);
node->data.fn_proto.name = fn_name;
node->data.fn_proto.is_extern = fn_type->data.fn.fn_type_id.is_extern;
node->data.fn_proto.top_level_decl.visib_mod = c->visib_mod;
@ -731,7 +731,7 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) {
normalize_parent_ptrs(node);
c->fn_table.put(buf_create_from_buf(&fn_name), true);
c->fn_table.put(buf_create_from_buf(fn_name), true);
c->root->data.root.top_level_decls.append(node);
}
@ -937,7 +937,7 @@ static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) {
if (enum_type->data.enumeration.complete) {
// now create top level decl for the type
AstNode *enum_node = create_node(c, NodeTypeContainerDecl);
buf_init_from_buf(&enum_node->data.struct_decl.name, &enum_type->name);
enum_node->data.struct_decl.name = &enum_type->name;
enum_node->data.struct_decl.kind = ContainerKindEnum;
enum_node->data.struct_decl.top_level_decl.visib_mod = VisibModExport;
enum_node->data.struct_decl.type_entry = enum_type;
@ -1114,7 +1114,7 @@ static void visit_record_decl(Context *c, const RecordDecl *record_decl) {
if (struct_type->data.structure.complete) {
// now create a top level decl node for the type
AstNode *struct_node = create_node(c, NodeTypeContainerDecl);
buf_init_from_buf(&struct_node->data.struct_decl.name, &struct_type->name);
struct_node->data.struct_decl.name = &struct_type->name;
struct_node->data.struct_decl.kind = ContainerKindStruct;
struct_node->data.struct_decl.top_level_decl.visib_mod = VisibModExport;
struct_node->data.struct_decl.type_entry = struct_type;
@ -1284,7 +1284,7 @@ static void render_aliases(Context *c) {
for (int i = 0; i < c->aliases.length; i += 1) {
AstNode *alias_node = c->aliases.at(i);
assert(alias_node->type == NodeTypeVariableDeclaration);
Buf *name = &alias_node->data.variable_declaration.symbol;
Buf *name = alias_node->data.variable_declaration.symbol;
if (name_exists(c, name)) {
continue;
}
@ -1327,7 +1327,7 @@ static void process_macro(Context *c, CTokenize *ctok, Buf *name, const char *ch
case CTokIdStrLit:
if (is_last && is_first) {
AstNode *var_node = create_var_decl_node(c, buf_ptr(name),
create_str_lit_node(c, &tok->data.str_lit));
create_str_lit_node(c, buf_create_from_buf(&tok->data.str_lit)));
c->macro_table.put(name, var_node);
}
return;

View File

@ -21,6 +21,9 @@ struct ParseContext {
ImportTableEntry *owner;
ErrColor err_color;
uint32_t *next_node_index;
// These buffers are used freqently so we preallocate them once here.
Buf *void_buf;
Buf *empty_buf;
};
__attribute__ ((format (printf, 4, 5)))
@ -29,7 +32,9 @@ static void ast_asm_error(ParseContext *pc, AstNode *node, int offset, const cha
assert(node->type == NodeTypeAsmExpr);
SrcPos pos = node->data.asm_expr.offset_map.at(offset);
// TODO calculate or otherwise keep track of originating line/column number for strings
//SrcPos pos = node->data.asm_expr.offset_map.at(offset);
SrcPos pos = { node->line, node->column };
va_list ap;
va_start(ap, format);
@ -83,12 +88,12 @@ static AstNode *ast_create_node(ParseContext *pc, NodeType type, Token *first_to
static AstNode *ast_create_void_type_node(ParseContext *pc, Token *token) {
AstNode *node = ast_create_node(pc, NodeTypeSymbol, token);
buf_init_from_str(&node->data.symbol_expr.symbol, "void");
node->data.symbol_expr.symbol = pc->void_buf;
return node;
}
static void parse_asm_template(ParseContext *pc, AstNode *node) {
Buf *asm_template = &node->data.asm_expr.asm_template;
Buf *asm_template = node->data.asm_expr.asm_template;
enum State {
StateStart,
@ -170,514 +175,29 @@ static void parse_asm_template(ParseContext *pc, AstNode *node) {
}
}
static uint8_t parse_char_literal(ParseContext *pc, Token *token) {
// skip the single quotes at beginning and end
// convert escape sequences
bool escape = false;
int return_count = 0;
uint8_t return_value;
for (int i = token->start_pos + 1; i < token->end_pos - 1; i += 1) {
uint8_t c = *((uint8_t*)buf_ptr(pc->buf) + i);
if (escape) {
switch (c) {
case '\\':
return_value = '\\';
return_count += 1;
break;
case 'r':
return_value = '\r';
return_count += 1;
break;
case 'n':
return_value = '\n';
return_count += 1;
break;
case 't':
return_value = '\t';
return_count += 1;
break;
case '\'':
return_value = '\'';
return_count += 1;
break;
default:
ast_error(pc, token, "invalid escape character");
}
escape = false;
} else if (c == '\\') {
escape = true;
} else {
return_value = c;
return_count += 1;
}
}
if (return_count == 0) {
ast_error(pc, token, "character literal too short");
} else if (return_count > 1) {
ast_error(pc, token, "character literal too long");
}
return return_value;
static Buf *token_buf(Token *token) {
assert(token->id == TokenIdStringLiteral || token->id == TokenIdSymbol);
return &token->data.str_lit.str;
}
static uint32_t get_hex_digit(uint8_t c) {
switch (c) {
case '0': return 0;
case '1': return 1;
case '2': return 2;
case '3': return 3;
case '4': return 4;
case '5': return 5;
case '6': return 6;
case '7': return 7;
case '8': return 8;
case '9': return 9;
case 'a':
case 'A':
return 10;
case 'b':
case 'B':
return 11;
case 'c':
case 'C':
return 12;
case 'd':
case 'D':
return 13;
case 'e':
case 'E':
return 14;
case 'f':
case 'F':
return 15;
default:
return UINT32_MAX;
}
static BigNum *token_bignum(Token *token) {
assert(token->id == TokenIdNumberLiteral);
return &token->data.num_lit.bignum;
}
static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf, bool *out_c_str,
ZigList<SrcPos> *offset_map)
{
if (token->raw_string_start > 0) {
uint8_t c1 = *((uint8_t*)buf_ptr(pc->buf) + token->start_pos);
uint8_t c2 = *((uint8_t*)buf_ptr(pc->buf) + token->start_pos + 1);
assert(c1 == 'r');
if (out_c_str) {
*out_c_str = (c2 == 'c');
}
const char *str = buf_ptr(pc->buf) + token->raw_string_start;
buf_init_from_mem(buf, str, token->raw_string_end - token->raw_string_start);
if (offset_map) {
SrcPos pos = {token->start_line, token->start_column};
for (int i = token->start_pos; i < token->raw_string_start; i += 1) {
uint8_t c = buf_ptr(pc->buf)[i];
if (c == '\n') {
pos.line += 1;
pos.column = 0;
} else {
pos.column += 1;
}
}
for (int i = token->raw_string_start; i < token->raw_string_end; i += 1) {
offset_map->append(pos);
uint8_t c = buf_ptr(pc->buf)[i];
if (c == '\n') {
pos.line += 1;
pos.column = 0;
} else {
pos.column += 1;
}
}
}
return;
}
// skip the double quotes at beginning and end
// convert escape sequences
// detect c string literal
enum State {
StatePre,
StateSkipQuot,
StateStart,
StateEscape,
StateHex1,
StateHex2,
StateUnicode,
};
buf_resize(buf, 0);
int unicode_index;
int unicode_end;
State state = StatePre;
SrcPos pos = {token->start_line, token->start_column};
uint32_t hex_value = 0;
for (int i = token->start_pos; i < token->end_pos - 1; i += 1) {
uint8_t c = *((uint8_t*)buf_ptr(pc->buf) + i);
switch (state) {
case StatePre:
switch (c) {
case '@':
state = StateSkipQuot;
break;
case 'c':
if (out_c_str) {
*out_c_str = true;
} else {
ast_error(pc, token, "C string literal not allowed here");
}
state = StateSkipQuot;
break;
case '"':
state = StateStart;
break;
default:
ast_error(pc, token, "invalid string character");
}
break;
case StateSkipQuot:
state = StateStart;
break;
case StateStart:
if (c == '\\') {
state = StateEscape;
} else {
buf_append_char(buf, c);
if (offset_map) offset_map->append(pos);
}
break;
case StateEscape:
switch (c) {
case '\\':
buf_append_char(buf, '\\');
if (offset_map) offset_map->append(pos);
state = StateStart;
break;
case 'r':
buf_append_char(buf, '\r');
if (offset_map) offset_map->append(pos);
state = StateStart;
break;
case 'n':
buf_append_char(buf, '\n');
if (offset_map) offset_map->append(pos);
state = StateStart;
break;
case 't':
buf_append_char(buf, '\t');
if (offset_map) offset_map->append(pos);
state = StateStart;
break;
case '"':
buf_append_char(buf, '"');
if (offset_map) offset_map->append(pos);
state = StateStart;
break;
case '\'':
buf_append_char(buf, '\'');
if (offset_map) offset_map->append(pos);
state = StateStart;
break;
case 'x':
state = StateHex1;
break;
case 'u':
state = StateUnicode;
unicode_index = 0;
unicode_end = 4;
hex_value = 0;
break;
case 'U':
state = StateUnicode;
unicode_index = 0;
unicode_end = 6;
hex_value = 0;
break;
default:
ast_error(pc, token, "invalid escape character");
}
break;
case StateHex1:
{
uint32_t hex_digit = get_hex_digit(c);
if (hex_digit == UINT32_MAX) {
ast_error(pc, token, "invalid hex digit: '%c'", c);
}
hex_value = hex_digit * 16;
state = StateHex2;
break;
}
case StateHex2:
{
uint32_t hex_digit = get_hex_digit(c);
if (hex_digit == UINT32_MAX) {
ast_error(pc, token, "invalid hex digit: '%c'", c);
}
hex_value += hex_digit;
assert(hex_value >= 0 && hex_value <= 255);
buf_append_char(buf, hex_value);
state = StateStart;
break;
}
case StateUnicode:
{
uint32_t hex_digit = get_hex_digit(c);
if (hex_digit == UINT32_MAX) {
ast_error(pc, token, "invalid hex digit: '%c'", c);
}
hex_value *= 16;
hex_value += hex_digit;
unicode_index += 1;
if (unicode_index >= unicode_end) {
if (hex_value <= 0x7f) {
// 00000000 00000000 00000000 0xxxxxxx
buf_append_char(buf, hex_value);
} else if (hex_value <= 0x7ff) {
// 00000000 00000000 00000xxx xx000000
buf_append_char(buf, (unsigned char)(0xc0 | (hex_value >> 6)));
// 00000000 00000000 00000000 00xxxxxx
buf_append_char(buf, (unsigned char)(0x80 | (hex_value & 0x3f)));
} else if (hex_value <= 0xffff) {
// 00000000 00000000 xxxx0000 00000000
buf_append_char(buf, (unsigned char)(0xe0 | (hex_value >> 12)));
// 00000000 00000000 0000xxxx xx000000
buf_append_char(buf, (unsigned char)(0x80 | ((hex_value >> 6) & 0x3f)));
// 00000000 00000000 00000000 00xxxxxx
buf_append_char(buf, (unsigned char)(0x80 | (hex_value & 0x3f)));
} else if (hex_value <= 0x10ffff) {
// 00000000 000xxx00 00000000 00000000
buf_append_char(buf, (unsigned char)(0xf0 | (hex_value >> 18)));
// 00000000 000000xx xxxx0000 00000000
buf_append_char(buf, (unsigned char)(0x80 | ((hex_value >> 12) & 0x3f)));
// 00000000 00000000 0000xxxx xx000000
buf_append_char(buf, (unsigned char)(0x80 | ((hex_value >> 6) & 0x3f)));
// 00000000 00000000 00000000 00xxxxxx
buf_append_char(buf, (unsigned char)(0x80 | (hex_value & 0x3f)));
} else {
ast_error(pc, token, "unicode value out of range: %x", hex_value);
}
state = StateStart;
}
break;
}
}
if (c == '\n') {
pos.line += 1;
pos.column = 0;
} else {
pos.column += 1;
}
}
assert(state == StateStart);
if (offset_map) offset_map->append(pos);
static uint8_t token_char_lit(Token *token) {
assert(token->id == TokenIdCharLiteral);
return token->data.char_lit.c;
}
static void ast_buf_from_token(ParseContext *pc, Token *token, Buf *buf) {
uint8_t *first_char = (uint8_t *)buf_ptr(pc->buf) + token->start_pos;
bool at_sign = *first_char == '@';
if (at_sign) {
parse_string_literal(pc, token, buf, nullptr, nullptr);
if (token->id == TokenIdSymbol) {
buf_init_from_buf(buf, token_buf(token));
} else {
buf_init_from_mem(buf, buf_ptr(pc->buf) + token->start_pos, token->end_pos - token->start_pos);
}
}
static unsigned long long parse_int_digits(ParseContext *pc, int digits_start, int digits_end, int radix,
int skip_index, bool *overflow)
{
unsigned long long x = 0;
for (int i = digits_start; i < digits_end; i++) {
if (i == skip_index)
continue;
uint8_t c = *((uint8_t*)buf_ptr(pc->buf) + i);
unsigned long long digit = get_digit_value(c);
// x *= radix;
if (__builtin_umulll_overflow(x, radix, &x)) {
*overflow = true;
return 0;
}
// x += digit
if (__builtin_uaddll_overflow(x, digit, &x)) {
*overflow = true;
return 0;
}
}
return x;
}
static void parse_number_literal(ParseContext *pc, Token *token, AstNodeNumberLiteral *num_lit) {
assert(token->id == TokenIdNumberLiteral);
int whole_number_start = token->start_pos;
if (token->radix != 10) {
// skip the "0x"
whole_number_start += 2;
}
int whole_number_end = token->decimal_point_pos;
if (whole_number_end <= whole_number_start) {
// TODO: error for empty whole number part
num_lit->overflow = true;
return;
}
if (token->decimal_point_pos == token->end_pos) {
// integer
unsigned long long whole_number = parse_int_digits(pc, whole_number_start, whole_number_end,
token->radix, -1, &num_lit->overflow);
if (num_lit->overflow) return;
num_lit->data.x_uint = whole_number;
num_lit->kind = NumLitUInt;
} else {
// float
if (token->radix == 10) {
// use a third-party base-10 float parser
char *str_begin = buf_ptr(pc->buf) + whole_number_start;
char *str_end;
errno = 0;
double x = strtod(str_begin, &str_end);
if (errno) {
// TODO: forward error to user
num_lit->overflow = true;
return;
}
assert(str_end == buf_ptr(pc->buf) + token->end_pos);
num_lit->data.x_float = x;
num_lit->kind = NumLitFloat;
return;
}
if (token->decimal_point_pos < token->exponent_marker_pos) {
// fraction
int fraction_start = token->decimal_point_pos + 1;
int fraction_end = token->exponent_marker_pos;
if (fraction_end <= fraction_start) {
// TODO: error for empty fraction part
num_lit->overflow = true;
return;
}
}
// trim leading and trailing zeros in the significand digit sequence
int significand_start = whole_number_start;
for (; significand_start < token->exponent_marker_pos; significand_start++) {
if (significand_start == token->decimal_point_pos)
continue;
uint8_t c = *((uint8_t*)buf_ptr(pc->buf) + significand_start);
if (c != '0')
break;
}
int significand_end = token->exponent_marker_pos;
for (; significand_end - 1 > significand_start; significand_end--) {
if (significand_end - 1 <= token->decimal_point_pos) {
significand_end = token->decimal_point_pos;
break;
}
uint8_t c = *((uint8_t*)buf_ptr(pc->buf) + significand_end - 1);
if (c != '0')
break;
}
unsigned long long significand_as_int = parse_int_digits(pc, significand_start, significand_end,
token->radix, token->decimal_point_pos, &num_lit->overflow);
if (num_lit->overflow) return;
int exponent_in_bin_or_dec = 0;
if (significand_end > token->decimal_point_pos) {
exponent_in_bin_or_dec = token->decimal_point_pos + 1 - significand_end;
if (token->radix == 2) {
// already good
} else if (token->radix == 8) {
exponent_in_bin_or_dec *= 3;
} else if (token->radix == 10) {
// already good
} else if (token->radix == 16) {
exponent_in_bin_or_dec *= 4;
} else zig_unreachable();
}
if (token->exponent_marker_pos < token->end_pos) {
// exponent
int exponent_start = token->exponent_marker_pos + 1;
int exponent_end = token->end_pos;
if (exponent_end <= exponent_start) {
// TODO: error for empty exponent part
num_lit->overflow = true;
return;
}
bool is_exponent_negative = false;
uint8_t c = *((uint8_t*)buf_ptr(pc->buf) + exponent_start);
if (c == '+') {
exponent_start += 1;
} else if (c == '-') {
exponent_start += 1;
is_exponent_negative = true;
}
if (exponent_end <= exponent_start) {
// TODO: error for empty exponent part
num_lit->overflow = true;
return;
}
unsigned long long specified_exponent = parse_int_digits(pc, exponent_start, exponent_end,
10, -1, &num_lit->overflow);
// TODO: this check is a little silly
if (specified_exponent >= LLONG_MAX) {
num_lit->overflow = true;
return;
}
if (is_exponent_negative) {
exponent_in_bin_or_dec -= specified_exponent;
} else {
exponent_in_bin_or_dec += specified_exponent;
}
}
uint64_t significand_bits;
uint64_t exponent_bits;
if (significand_as_int != 0) {
// normalize the significand
if (token->radix == 10) {
zig_panic("TODO: decimal floats");
} else {
int significand_magnitude_in_bin = __builtin_clzll(1) - __builtin_clzll(significand_as_int);
exponent_in_bin_or_dec += significand_magnitude_in_bin;
if (!(-1023 <= exponent_in_bin_or_dec && exponent_in_bin_or_dec < 1023)) {
num_lit->overflow = true;
return;
}
// this should chop off exactly one 1 bit from the top.
significand_bits = ((uint64_t)significand_as_int << (52 - significand_magnitude_in_bin)) & 0xfffffffffffffULL;
exponent_bits = exponent_in_bin_or_dec + 1023;
}
} else {
// 0 is all 0's
significand_bits = 0;
exponent_bits = 0;
}
uint64_t double_bits = (exponent_bits << 52) | significand_bits;
double x = *(double *)&double_bits;
num_lit->data.x_float = x;
num_lit->kind = NumLitFloat;
}
}
__attribute__ ((noreturn))
static void ast_invalid_token_error(ParseContext *pc, Token *token) {
Buf token_value = BUF_INIT;
@ -723,7 +243,7 @@ static AstNode *ast_parse_directive(ParseContext *pc, int *token_index) {
Token *name_symbol = ast_eat_token(pc, token_index, TokenIdSymbol);
ast_buf_from_token(pc, name_symbol, &node->data.directive.name);
node->data.directive.name = token_buf(name_symbol);
node->data.directive.expr = ast_parse_grouped_expr(pc, token_index, true);
@ -769,12 +289,12 @@ static AstNode *ast_parse_param_decl(ParseContext *pc, int *token_index) {
token = &pc->tokens->at(*token_index);
}
buf_resize(&node->data.param_decl.name, 0);
node->data.param_decl.name = pc->empty_buf;
if (token->id == TokenIdSymbol) {
Token *next_token = &pc->tokens->at(*token_index + 1);
if (next_token->id == TokenIdColon) {
ast_buf_from_token(pc, token, &node->data.param_decl.name);
node->data.param_decl.name = token_buf(token);
*token_index += 2;
}
}
@ -915,8 +435,8 @@ static void ast_parse_asm_input_item(ParseContext *pc, int *token_index, AstNode
ast_eat_token(pc, token_index, TokenIdRParen);
AsmInput *asm_input = allocate<AsmInput>(1);
ast_buf_from_token(pc, alias, &asm_input->asm_symbolic_name);
parse_string_literal(pc, constraint, &asm_input->constraint, nullptr, nullptr);
asm_input->asm_symbolic_name = token_buf(alias);
asm_input->constraint = token_buf(constraint);
asm_input->expr = expr_node;
node->data.asm_expr.input_list.append(asm_input);
}
@ -938,7 +458,7 @@ static void ast_parse_asm_output_item(ParseContext *pc, int *token_index, AstNod
Token *token = &pc->tokens->at(*token_index);
*token_index += 1;
if (token->id == TokenIdSymbol) {
ast_buf_from_token(pc, token, &asm_output->variable_name);
asm_output->variable_name = token_buf(token);
} else if (token->id == TokenIdArrow) {
asm_output->return_type = ast_parse_prefix_op_expr(pc, token_index, true);
} else {
@ -947,8 +467,8 @@ static void ast_parse_asm_output_item(ParseContext *pc, int *token_index, AstNod
ast_eat_token(pc, token_index, TokenIdRParen);
ast_buf_from_token(pc, alias, &asm_output->asm_symbolic_name);
parse_string_literal(pc, constraint, &asm_output->constraint, nullptr, nullptr);
asm_output->asm_symbolic_name = token_buf(alias);
asm_output->constraint = token_buf(constraint);
node->data.asm_expr.output_list.append(asm_output);
}
@ -968,8 +488,7 @@ static void ast_parse_asm_clobbers(ParseContext *pc, int *token_index, AstNode *
ast_expect_token(pc, string_tok, TokenIdStringLiteral);
*token_index += 1;
Buf *clobber_buf = buf_alloc();
parse_string_literal(pc, string_tok, clobber_buf, nullptr, nullptr);
Buf *clobber_buf = token_buf(string_tok);
node->data.asm_expr.clobber_list.append(clobber_buf);
Token *comma = &pc->tokens->at(*token_index);
@ -1072,19 +591,14 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, int *token_index, bool mand
ast_expect_token(pc, lparen_tok, TokenIdLParen);
*token_index += 1;
Token *template_tok = &pc->tokens->at(*token_index);
ast_expect_token(pc, template_tok, TokenIdStringLiteral);
*token_index += 1;
Token *template_tok = ast_eat_token(pc, token_index, TokenIdStringLiteral);
parse_string_literal(pc, template_tok, &node->data.asm_expr.asm_template, nullptr,
&node->data.asm_expr.offset_map);
node->data.asm_expr.asm_template = token_buf(template_tok);
parse_asm_template(pc, node);
ast_parse_asm_output(pc, token_index, node);
Token *rparen_tok = &pc->tokens->at(*token_index);
ast_expect_token(pc, rparen_tok, TokenIdRParen);
*token_index += 1;
ast_eat_token(pc, token_index, TokenIdRParen);
normalize_parent_ptrs(node);
return node;
@ -1099,17 +613,19 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
if (token->id == TokenIdNumberLiteral) {
AstNode *node = ast_create_node(pc, NodeTypeNumberLiteral, token);
parse_number_literal(pc, token, &node->data.number_literal);
node->data.number_literal.bignum = token_bignum(token);
node->data.number_literal.overflow = token->data.num_lit.overflow;
*token_index += 1;
return node;
} else if (token->id == TokenIdStringLiteral) {
AstNode *node = ast_create_node(pc, NodeTypeStringLiteral, token);
parse_string_literal(pc, token, &node->data.string_literal.buf, &node->data.string_literal.c, nullptr);
node->data.string_literal.buf = token_buf(token);
node->data.string_literal.c = token->data.str_lit.is_c_str;
*token_index += 1;
return node;
} else if (token->id == TokenIdCharLiteral) {
AstNode *node = ast_create_node(pc, NodeTypeCharLiteral, token);
node->data.char_literal.value = parse_char_literal(pc, token);
node->data.char_literal.value = token_char_lit(token);
*token_index += 1;
return node;
} else if (token->id == TokenIdKeywordTrue) {
@ -1155,7 +671,7 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
*token_index += 1;
Token *name_tok = ast_eat_token(pc, token_index, TokenIdSymbol);
AstNode *name_node = ast_create_node(pc, NodeTypeSymbol, name_tok);
ast_buf_from_token(pc, name_tok, &name_node->data.symbol_expr.symbol);
name_node->data.symbol_expr.symbol = token_buf(name_tok);
AstNode *node = ast_create_node(pc, NodeTypeFnCallExpr, token);
node->data.fn_call_expr.fn_ref_expr = name_node;
@ -1168,7 +684,7 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
} else if (token->id == TokenIdSymbol) {
*token_index += 1;
AstNode *node = ast_create_node(pc, NodeTypeSymbol, token);
ast_buf_from_token(pc, token, &node->data.symbol_expr.symbol);
node->data.symbol_expr.symbol = token_buf(token);
return node;
} else if (token->id == TokenIdKeywordGoto) {
AstNode *node = ast_create_node(pc, NodeTypeGoto, token);
@ -1178,7 +694,7 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
*token_index += 1;
ast_expect_token(pc, dest_symbol, TokenIdSymbol);
ast_buf_from_token(pc, dest_symbol, &node->data.goto_expr.name);
node->data.goto_expr.name = token_buf(dest_symbol);
return node;
}
@ -1243,7 +759,7 @@ static AstNode *ast_parse_curly_suffix_expr(ParseContext *pc, int *token_index,
AstNode *field_node = ast_create_node(pc, NodeTypeStructValueField, token);
ast_buf_from_token(pc, field_name_tok, &field_node->data.struct_val_field.name);
field_node->data.struct_val_field.name = token_buf(field_name_tok);
field_node->data.struct_val_field.expr = ast_parse_expression(pc, token_index, true);
normalize_parent_ptrs(field_node);
@ -1370,7 +886,7 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, int *token_index, boo
AstNode *node = ast_create_node(pc, NodeTypeFieldAccessExpr, first_token);
node->data.field_access_expr.struct_expr = primary_expr;
ast_buf_from_token(pc, name_token, &node->data.field_access_expr.field_name);
node->data.field_access_expr.field_name = token_buf(name_token);
normalize_parent_ptrs(node);
primary_expr = node;
@ -1819,10 +1335,10 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool manda
*token_index += 1;
node->data.if_var_expr.var_is_ptr = true;
Token *name_token = ast_eat_token(pc, token_index, TokenIdSymbol);
ast_buf_from_token(pc, name_token, &node->data.if_var_expr.var_decl.symbol);
node->data.if_var_expr.var_decl.symbol = token_buf(name_token);
} else if (star_or_symbol->id == TokenIdSymbol) {
*token_index += 1;
ast_buf_from_token(pc, star_or_symbol, &node->data.if_var_expr.var_decl.symbol);
node->data.if_var_expr.var_decl.symbol = token_buf(star_or_symbol);
} else {
ast_invalid_token_error(pc, star_or_symbol);
}
@ -1974,7 +1490,7 @@ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, int *token
node->data.variable_declaration.top_level_decl.directives = directives;
Token *name_token = ast_eat_token(pc, token_index, TokenIdSymbol);
ast_buf_from_token(pc, name_token, &node->data.variable_declaration.symbol);
node->data.variable_declaration.symbol = token_buf(name_token);
Token *eq_or_colon = &pc->tokens->at(*token_index);
*token_index += 1;
@ -2067,7 +1583,7 @@ static AstNode *ast_parse_while_expr(ParseContext *pc, int *token_index, bool ma
static AstNode *ast_parse_symbol(ParseContext *pc, int *token_index) {
Token *token = ast_eat_token(pc, token_index, TokenIdSymbol);
AstNode *node = ast_create_node(pc, NodeTypeSymbol, token);
ast_buf_from_token(pc, token, &node->data.symbol_expr.symbol);
node->data.symbol_expr.symbol = token_buf(token);
return node;
}
@ -2405,7 +1921,7 @@ static AstNode *ast_parse_label(ParseContext *pc, int *token_index, bool mandato
*token_index += 2;
AstNode *node = ast_create_node(pc, NodeTypeLabel, symbol_token);
ast_buf_from_token(pc, symbol_token, &node->data.label.name);
node->data.label.name = token_buf(symbol_token);
return node;
}
@ -2413,7 +1929,7 @@ static AstNode *ast_create_void_expr(ParseContext *pc, Token *token) {
AstNode *node = ast_create_node(pc, NodeTypeContainerInitExpr, token);
node->data.container_init_expr.type = ast_create_node(pc, NodeTypeSymbol, token);
node->data.container_init_expr.kind = ContainerInitKindArray;
buf_init_from_str(&node->data.container_init_expr.type->data.symbol_expr.symbol, "void");
node->data.container_init_expr.type->data.symbol_expr.symbol = pc->void_buf;
normalize_parent_ptrs(node);
return node;
}
@ -2508,9 +2024,9 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mand
Token *fn_name = &pc->tokens->at(*token_index);
if (fn_name->id == TokenIdSymbol) {
*token_index += 1;
ast_buf_from_token(pc, fn_name, &node->data.fn_proto.name);
node->data.fn_proto.name = token_buf(fn_name);
} else {
buf_resize(&node->data.fn_proto.name, 0);
node->data.fn_proto.name = pc->empty_buf;
}
ast_parse_param_decl_list(pc, token_index, &node->data.fn_proto.params, &node->data.fn_proto.is_var_args);
@ -2663,7 +2179,7 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, int *token_index,
AstNode *node = ast_create_node(pc, NodeTypeContainerDecl, first_token);
node->data.struct_decl.kind = kind;
ast_buf_from_token(pc, struct_name, &node->data.struct_decl.name);
node->data.struct_decl.name = token_buf(struct_name);
node->data.struct_decl.top_level_decl.visib_mod = visib_mod;
node->data.struct_decl.top_level_decl.directives = directives;
@ -2729,8 +2245,7 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, int *token_index,
field_node->data.struct_field.top_level_decl.visib_mod = visib_mod;
field_node->data.struct_field.top_level_decl.directives = directive_list;
ast_buf_from_token(pc, token, &field_node->data.struct_field.name);
field_node->data.struct_field.name = token_buf(token);
Token *expr_or_comma = &pc->tokens->at(*token_index);
if (expr_or_comma->id == TokenIdComma) {
@ -2772,7 +2287,7 @@ static AstNode *ast_parse_error_value_decl(ParseContext *pc, int *token_index,
AstNode *node = ast_create_node(pc, NodeTypeErrorValueDecl, first_token);
node->data.error_value_decl.top_level_decl.visib_mod = visib_mod;
node->data.error_value_decl.top_level_decl.directives = directives;
ast_buf_from_token(pc, name_tok, &node->data.error_value_decl.name);
node->data.error_value_decl.name = token_buf(name_tok);
normalize_parent_ptrs(node);
return node;
@ -2795,7 +2310,7 @@ static AstNode *ast_parse_type_decl(ParseContext *pc, int *token_index,
ast_eat_token(pc, token_index, TokenIdEq);
AstNode *node = ast_create_node(pc, NodeTypeTypeDecl, first_token);
ast_buf_from_token(pc, name_tok, &node->data.type_decl.symbol);
node->data.type_decl.symbol = token_buf(name_tok);
node->data.type_decl.child_type = ast_parse_prefix_op_expr(pc, token_index, true);
ast_eat_token(pc, token_index, TokenIdSemicolon);
@ -2901,6 +2416,8 @@ AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens, ImportTableEntry *owner,
ErrColor err_color, uint32_t *next_node_index)
{
ParseContext pc = {0};
pc.void_buf = buf_create_from_str("void");
pc.empty_buf = buf_create_from_str("");
pc.err_color = err_color;
pc.owner = owner;
pc.buf = buf;

File diff suppressed because it is too large Load Diff

View File

@ -9,6 +9,7 @@
#define ZIG_TOKENIZER_HPP
#include "buffer.hpp"
#include "bignum.hpp"
enum TokenId {
TokenIdEof,
@ -111,6 +112,22 @@ enum TokenId {
TokenIdPercentDot,
};
struct TokenNumLit {
BigNum bignum;
// overflow is true if when parsing the number, we discovered it would not
// fit without losing data in a uint64_t or double
bool overflow;
};
struct TokenStrLit {
Buf str;
bool is_c_str;
};
struct TokenCharLit {
uint8_t c;
};
struct Token {
TokenId id;
int start_pos;
@ -118,14 +135,16 @@ struct Token {
int start_line;
int start_column;
// for id == TokenIdNumberLiteral
int radix; // if != 10, then skip the first 2 characters
int decimal_point_pos; // either exponent_marker_pos or the position of the '.'
int exponent_marker_pos; // either end_pos or the position of the 'e'/'p'
union {
// TokenIdNumberLiteral
TokenNumLit num_lit;
// for id == TokenIdStringLiteral
int raw_string_start;
int raw_string_end;
// TokenIdStringLiteral or TokenIdSymbol
TokenStrLit str_lit;
// TokenIdCharLiteral
TokenCharLit char_lit;
} data;
};
struct Tokenization {
@ -142,8 +161,6 @@ void tokenize(Buf *buf, Tokenization *out_tokenization);
void print_tokens(Buf *buf, ZigList<Token> *tokens);
int get_digit_value(uint8_t c);
const char * token_name(TokenId id);
bool valid_symbol_starter(uint8_t c);

View File

@ -1173,7 +1173,7 @@ fn f() {
add_compile_fail_case("normal string with newline", R"SOURCE(
const foo = "a
b";
)SOURCE", 1, ".tmp_source.zig:2:13: error: use raw string for multiline string literal");
)SOURCE", 1, ".tmp_source.zig:2:13: error: newline not allowed in string literal");
add_compile_fail_case("invalid comparison for function pointers", R"SOURCE(
fn foo() {}
@ -1760,7 +1760,7 @@ struct type {
)SOURCE", 3,
R"(pub const FOO = c"aoeu\x13 derp")",
R"(pub const FOO2 = c"aoeu\x134 derp")",
R"(pub const FOO_CHAR = '\x3f')");
R"(pub const FOO_CHAR = '?')");
}
static void run_self_hosted_test(bool is_release_mode) {

View File

@ -684,17 +684,13 @@ fn count_trailing_zeroes() {
#attribute("test")
fn multiline_string() {
const s1 = r"AOEU(
one
two)
three)AOEU";
const s2 = "\none\ntwo)\nthree";
const s3 = r"(
one
two)
three)";
const s1 =
\\one
\\two)
\\three
;
const s2 = "one\ntwo)\nthree";
assert(str.eql(s1, s2));
assert(str.eql(s3, s2));
}