| /** |
| * Defines lexical tokens. |
| * |
| * Specification: $(LINK2 https://dlang.org/spec/lex.html#tokens, Tokens) |
| * |
| * Copyright: Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved |
| * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) |
| * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) |
| * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/tokens.d, _tokens.d) |
| * Documentation: https://dlang.org/phobos/dmd_tokens.html |
| * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/tokens.d |
| */ |
| |
| module dmd.tokens; |
| |
| import core.stdc.ctype; |
| import core.stdc.stdio; |
| import core.stdc.string; |
| import dmd.globals; |
| import dmd.identifier; |
| import dmd.root.ctfloat; |
| import dmd.common.outbuffer; |
| import dmd.root.rmem; |
| import dmd.root.utf; |
| |
| enum TOK : ubyte |
| { |
| reserved, |
| |
| // Other |
| leftParenthesis, |
| rightParenthesis, |
| leftBracket, |
| rightBracket, |
| leftCurly, |
| rightCurly, |
| colon, |
| semicolon, |
| dotDotDot, |
| endOfFile, |
| cast_, |
| null_, |
| assert_, |
| true_, |
| false_, |
| throw_, |
| new_, |
| delete_, |
| variable, |
| slice, |
| version_, |
| module_, |
| dollar, |
| template_, |
| typeof_, |
| pragma_, |
| typeid_, |
| comment, |
| |
| // Operators |
| lessThan, |
| greaterThan, |
| lessOrEqual, |
| greaterOrEqual, |
| equal, |
| notEqual, |
| identity, |
| notIdentity, |
| is_, |
| |
| leftShift, |
| rightShift, |
| leftShiftAssign, |
| rightShiftAssign, |
| unsignedRightShift, |
| unsignedRightShiftAssign, |
| concatenateAssign, // ~= |
| add, |
| min, |
| addAssign, |
| minAssign, |
| mul, |
| div, |
| mod, |
| mulAssign, |
| divAssign, |
| modAssign, |
| and, |
| or, |
| xor, |
| andAssign, |
| orAssign, |
| xorAssign, |
| assign, |
| not, |
| tilde, |
| plusPlus, |
| minusMinus, |
| dot, |
| comma, |
| question, |
| andAnd, |
| orOr, |
| |
| // Numeric literals |
| int32Literal, |
| uns32Literal, |
| int64Literal, |
| uns64Literal, |
| int128Literal, |
| uns128Literal, |
| float32Literal, |
| float64Literal, |
| float80Literal, |
| imaginary32Literal, |
| imaginary64Literal, |
| imaginary80Literal, |
| |
| // Char constants |
| charLiteral, |
| wcharLiteral, |
| dcharLiteral, |
| |
| // Leaf operators |
| identifier, |
| string_, |
| this_, |
| super_, |
| error, |
| |
| // Basic types |
| void_, |
| int8, |
| uns8, |
| int16, |
| uns16, |
| int32, |
| uns32, |
| int64, |
| uns64, |
| int128, |
| uns128, |
| float32, |
| float64, |
| float80, |
| imaginary32, |
| imaginary64, |
| imaginary80, |
| complex32, |
| complex64, |
| complex80, |
| char_, |
| wchar_, |
| dchar_, |
| bool_, |
| |
| // Aggregates |
| struct_, |
| class_, |
| interface_, |
| union_, |
| enum_, |
| import_, |
| alias_, |
| override_, |
| delegate_, |
| function_, |
| mixin_, |
| align_, |
| extern_, |
| private_, |
| protected_, |
| public_, |
| export_, |
| static_, |
| final_, |
| const_, |
| abstract_, |
| debug_, |
| deprecated_, |
| in_, |
| out_, |
| inout_, |
| lazy_, |
| auto_, |
| package_, |
| immutable_, |
| |
| // Statements |
| if_, |
| else_, |
| while_, |
| for_, |
| do_, |
| switch_, |
| case_, |
| default_, |
| break_, |
| continue_, |
| with_, |
| synchronized_, |
| return_, |
| goto_, |
| try_, |
| catch_, |
| finally_, |
| asm_, |
| foreach_, |
| foreach_reverse_, |
| scope_, |
| onScopeExit, |
| onScopeFailure, |
| onScopeSuccess, |
| |
| // Contracts |
| invariant_, |
| |
| // Testing |
| unittest_, |
| |
| // Added after 1.0 |
| argumentTypes, |
| ref_, |
| macro_, |
| |
| parameters, |
| traits, |
| pure_, |
| nothrow_, |
| gshared, |
| line, |
| file, |
| fileFullPath, |
| moduleString, // __MODULE__ |
| functionString, // __FUNCTION__ |
| prettyFunction, // __PRETTY_FUNCTION__ |
| shared_, |
| at, |
| pow, |
| powAssign, |
| goesTo, |
| vector, |
| pound, |
| |
| arrow, // -> |
| colonColon, // :: |
| wchar_tLiteral, |
| endOfLine, // \n, \r, \u2028, \u2029 |
| whitespace, |
| |
| // C only keywords |
| inline, |
| register, |
| restrict, |
| signed, |
| sizeof_, |
| typedef_, |
| unsigned, |
| volatile, |
| _Alignas, |
| _Alignof, |
| _Atomic, |
| _Bool, |
| _Complex, |
| _Generic, |
| _Imaginary, |
| _Noreturn, |
| _Static_assert, |
| _Thread_local, |
| |
| // C only extended keywords |
| _import, |
| __cdecl, |
| __declspec, |
| __stdcall, |
| __pragma, |
| __attribute__, |
| } |
| |
| /// Expression nodes |
| enum EXP : ubyte |
| { |
| reserved, |
| |
| // Other |
| negate, |
| cast_, |
| null_, |
| assert_, |
| true_, |
| false_, |
| array, |
| call, |
| address, |
| type, |
| throw_, |
| new_, |
| delete_, |
| star, |
| symbolOffset, |
| variable, |
| dotVariable, |
| dotIdentifier, |
| dotTemplateInstance, |
| dotType, |
| slice, |
| arrayLength, |
| version_, |
| dollar, |
| template_, |
| dotTemplateDeclaration, |
| declaration, |
| typeof_, |
| pragma_, |
| dSymbol, |
| typeid_, |
| uadd, |
| remove, |
| newAnonymousClass, |
| arrayLiteral, |
| assocArrayLiteral, |
| structLiteral, |
| classReference, |
| thrownException, |
| delegatePointer, |
| delegateFunctionPointer, |
| |
| // Operators |
| lessThan, |
| greaterThan, |
| lessOrEqual, |
| greaterOrEqual, |
| equal, |
| notEqual, |
| identity, |
| notIdentity, |
| index, |
| is_, |
| |
| leftShift, |
| rightShift, |
| leftShiftAssign, |
| rightShiftAssign, |
| unsignedRightShift, |
| unsignedRightShiftAssign, |
| concatenate, |
| concatenateAssign, // ~= |
| concatenateElemAssign, |
| concatenateDcharAssign, |
| add, |
| min, |
| addAssign, |
| minAssign, |
| mul, |
| div, |
| mod, |
| mulAssign, |
| divAssign, |
| modAssign, |
| and, |
| or, |
| xor, |
| andAssign, |
| orAssign, |
| xorAssign, |
| assign, |
| not, |
| tilde, |
| plusPlus, |
| minusMinus, |
| construct, |
| blit, |
| dot, |
| comma, |
| question, |
| andAnd, |
| orOr, |
| prePlusPlus, |
| preMinusMinus, |
| |
| // Leaf operators |
| identifier, |
| string_, |
| this_, |
| super_, |
| halt, |
| tuple, |
| error, |
| |
| // Basic types |
| void_, |
| int64, |
| float64, |
| complex80, |
| char_, |
| import_, |
| delegate_, |
| function_, |
| mixin_, |
| in_, |
| default_, |
| break_, |
| continue_, |
| goto_, |
| scope_, |
| |
| traits, |
| overloadSet, |
| line, |
| file, |
| fileFullPath, |
| moduleString, // __MODULE__ |
| functionString, // __FUNCTION__ |
| prettyFunction, // __PRETTY_FUNCTION__ |
| shared_, |
| pow, |
| powAssign, |
| vector, |
| |
| voidExpression, |
| cantExpression, |
| showCtfeContext, |
| objcClassReference, |
| vectorArray, |
| arrow, // -> |
| compoundLiteral, // ( type-name ) { initializer-list } |
| _Generic, |
| interval, |
| } |
| |
| enum FirstCKeyword = TOK.inline; |
| |
| // Assert that all token enum members have consecutive values and |
| // that none of them overlap |
| static assert(() { |
| foreach (idx, enumName; __traits(allMembers, TOK)) { |
| static if (idx != __traits(getMember, TOK, enumName)) { |
| pragma(msg, "Error: Expected TOK.", enumName, " to be ", idx, " but is ", __traits(getMember, TOK, enumName)); |
| static assert(0); |
| } |
| } |
| return true; |
| }()); |
| |
| /**************************************** |
| */ |
| |
| private immutable TOK[] keywords = |
| [ |
| TOK.this_, |
| TOK.super_, |
| TOK.assert_, |
| TOK.null_, |
| TOK.true_, |
| TOK.false_, |
| TOK.cast_, |
| TOK.new_, |
| TOK.delete_, |
| TOK.throw_, |
| TOK.module_, |
| TOK.pragma_, |
| TOK.typeof_, |
| TOK.typeid_, |
| TOK.template_, |
| TOK.void_, |
| TOK.int8, |
| TOK.uns8, |
| TOK.int16, |
| TOK.uns16, |
| TOK.int32, |
| TOK.uns32, |
| TOK.int64, |
| TOK.uns64, |
| TOK.int128, |
| TOK.uns128, |
| TOK.float32, |
| TOK.float64, |
| TOK.float80, |
| TOK.bool_, |
| TOK.char_, |
| TOK.wchar_, |
| TOK.dchar_, |
| TOK.imaginary32, |
| TOK.imaginary64, |
| TOK.imaginary80, |
| TOK.complex32, |
| TOK.complex64, |
| TOK.complex80, |
| TOK.delegate_, |
| TOK.function_, |
| TOK.is_, |
| TOK.if_, |
| TOK.else_, |
| TOK.while_, |
| TOK.for_, |
| TOK.do_, |
| TOK.switch_, |
| TOK.case_, |
| TOK.default_, |
| TOK.break_, |
| TOK.continue_, |
| TOK.synchronized_, |
| TOK.return_, |
| TOK.goto_, |
| TOK.try_, |
| TOK.catch_, |
| TOK.finally_, |
| TOK.with_, |
| TOK.asm_, |
| TOK.foreach_, |
| TOK.foreach_reverse_, |
| TOK.scope_, |
| TOK.struct_, |
| TOK.class_, |
| TOK.interface_, |
| TOK.union_, |
| TOK.enum_, |
| TOK.import_, |
| TOK.mixin_, |
| TOK.static_, |
| TOK.final_, |
| TOK.const_, |
| TOK.alias_, |
| TOK.override_, |
| TOK.abstract_, |
| TOK.debug_, |
| TOK.deprecated_, |
| TOK.in_, |
| TOK.out_, |
| TOK.inout_, |
| TOK.lazy_, |
| TOK.auto_, |
| TOK.align_, |
| TOK.extern_, |
| TOK.private_, |
| TOK.package_, |
| TOK.protected_, |
| TOK.public_, |
| TOK.export_, |
| TOK.invariant_, |
| TOK.unittest_, |
| TOK.version_, |
| TOK.argumentTypes, |
| TOK.parameters, |
| TOK.ref_, |
| TOK.macro_, |
| TOK.pure_, |
| TOK.nothrow_, |
| TOK.gshared, |
| TOK.traits, |
| TOK.vector, |
| TOK.file, |
| TOK.fileFullPath, |
| TOK.line, |
| TOK.moduleString, |
| TOK.functionString, |
| TOK.prettyFunction, |
| TOK.shared_, |
| TOK.immutable_, |
| |
| // C only keywords |
| TOK.inline, |
| TOK.register, |
| TOK.restrict, |
| TOK.signed, |
| TOK.sizeof_, |
| TOK.typedef_, |
| TOK.unsigned, |
| TOK.volatile, |
| TOK._Alignas, |
| TOK._Alignof, |
| TOK._Atomic, |
| TOK._Bool, |
| TOK._Complex, |
| TOK._Generic, |
| TOK._Imaginary, |
| TOK._Noreturn, |
| TOK._Static_assert, |
| TOK._Thread_local, |
| |
| // C only extended keywords |
| TOK._import, |
| TOK.__cdecl, |
| TOK.__declspec, |
| TOK.__stdcall, |
| TOK.__pragma, |
| TOK.__attribute__, |
| ]; |
| |
| // Initialize the identifier pool |
| shared static this() nothrow |
| { |
| Identifier.initTable(); |
| foreach (kw; keywords) |
| { |
| //printf("keyword[%d] = '%s'\n",kw, Token.tochars[kw].ptr); |
| Identifier.idPool(Token.tochars[kw].ptr, Token.tochars[kw].length, cast(uint)kw); |
| } |
| } |
| |
| /************************************ |
| * This is used to pick the C keywords out of the tokens. |
| * If it's not a C keyword, then it's an identifier. |
| */ |
| static immutable TOK[TOK.max + 1] Ckeywords = |
| () { |
| with (TOK) |
| { |
| TOK[TOK.max + 1] tab = identifier; // default to identifier |
| enum Ckwds = [ auto_, break_, case_, char_, const_, continue_, default_, do_, float64, else_, |
| enum_, extern_, float32, for_, goto_, if_, inline, int32, int64, register, |
| restrict, return_, int16, signed, sizeof_, static_, struct_, switch_, typedef_, |
| union_, unsigned, void_, volatile, while_, asm_, typeof_, |
| _Alignas, _Alignof, _Atomic, _Bool, _Complex, _Generic, _Imaginary, _Noreturn, |
| _Static_assert, _Thread_local, _import, __cdecl, __declspec, __stdcall, __pragma, __attribute__ ]; |
| |
| foreach (kw; Ckwds) |
| tab[kw] = cast(TOK) kw; |
| |
| return tab; |
| } |
| } (); |
| |
| |
| /*********************************************************** |
| */ |
| extern (C++) struct Token |
| { |
| Token* next; |
| Loc loc; |
| const(char)* ptr; // pointer to first character of this token within buffer |
| TOK value; |
| const(char)[] blockComment; // doc comment string prior to this token |
| const(char)[] lineComment; // doc comment for previous token |
| |
| union |
| { |
| // Integers |
| sinteger_t intvalue; |
| uinteger_t unsvalue; |
| // Floats |
| real_t floatvalue; |
| |
| struct |
| { |
| const(char)* ustring; // UTF8 string |
| uint len; |
| ubyte postfix; // 'c', 'w', 'd' |
| } |
| |
| Identifier ident; |
| } |
| |
| extern (D) private static immutable string[TOK.max + 1] tochars = |
| [ |
| // Keywords |
| TOK.this_: "this", |
| TOK.super_: "super", |
| TOK.assert_: "assert", |
| TOK.null_: "null", |
| TOK.true_: "true", |
| TOK.false_: "false", |
| TOK.cast_: "cast", |
| TOK.new_: "new", |
| TOK.delete_: "delete", |
| TOK.throw_: "throw", |
| TOK.module_: "module", |
| TOK.pragma_: "pragma", |
| TOK.typeof_: "typeof", |
| TOK.typeid_: "typeid", |
| TOK.template_: "template", |
| TOK.void_: "void", |
| TOK.int8: "byte", |
| TOK.uns8: "ubyte", |
| TOK.int16: "short", |
| TOK.uns16: "ushort", |
| TOK.int32: "int", |
| TOK.uns32: "uint", |
| TOK.int64: "long", |
| TOK.uns64: "ulong", |
| TOK.int128: "cent", |
| TOK.uns128: "ucent", |
| TOK.float32: "float", |
| TOK.float64: "double", |
| TOK.float80: "real", |
| TOK.bool_: "bool", |
| TOK.char_: "char", |
| TOK.wchar_: "wchar", |
| TOK.dchar_: "dchar", |
| TOK.imaginary32: "ifloat", |
| TOK.imaginary64: "idouble", |
| TOK.imaginary80: "ireal", |
| TOK.complex32: "cfloat", |
| TOK.complex64: "cdouble", |
| TOK.complex80: "creal", |
| TOK.delegate_: "delegate", |
| TOK.function_: "function", |
| TOK.is_: "is", |
| TOK.if_: "if", |
| TOK.else_: "else", |
| TOK.while_: "while", |
| TOK.for_: "for", |
| TOK.do_: "do", |
| TOK.switch_: "switch", |
| TOK.case_: "case", |
| TOK.default_: "default", |
| TOK.break_: "break", |
| TOK.continue_: "continue", |
| TOK.synchronized_: "synchronized", |
| TOK.return_: "return", |
| TOK.goto_: "goto", |
| TOK.try_: "try", |
| TOK.catch_: "catch", |
| TOK.finally_: "finally", |
| TOK.with_: "with", |
| TOK.asm_: "asm", |
| TOK.foreach_: "foreach", |
| TOK.foreach_reverse_: "foreach_reverse", |
| TOK.scope_: "scope", |
| TOK.struct_: "struct", |
| TOK.class_: "class", |
| TOK.interface_: "interface", |
| TOK.union_: "union", |
| TOK.enum_: "enum", |
| TOK.import_: "import", |
| TOK.mixin_: "mixin", |
| TOK.static_: "static", |
| TOK.final_: "final", |
| TOK.const_: "const", |
| TOK.alias_: "alias", |
| TOK.override_: "override", |
| TOK.abstract_: "abstract", |
| TOK.debug_: "debug", |
| TOK.deprecated_: "deprecated", |
| TOK.in_: "in", |
| TOK.out_: "out", |
| TOK.inout_: "inout", |
| TOK.lazy_: "lazy", |
| TOK.auto_: "auto", |
| TOK.align_: "align", |
| TOK.extern_: "extern", |
| TOK.private_: "private", |
| TOK.package_: "package", |
| TOK.protected_: "protected", |
| TOK.public_: "public", |
| TOK.export_: "export", |
| TOK.invariant_: "invariant", |
| TOK.unittest_: "unittest", |
| TOK.version_: "version", |
| TOK.argumentTypes: "__argTypes", |
| TOK.parameters: "__parameters", |
| TOK.ref_: "ref", |
| TOK.macro_: "macro", |
| TOK.pure_: "pure", |
| TOK.nothrow_: "nothrow", |
| TOK.gshared: "__gshared", |
| TOK.traits: "__traits", |
| TOK.vector: "__vector", |
| TOK.file: "__FILE__", |
| TOK.fileFullPath: "__FILE_FULL_PATH__", |
| TOK.line: "__LINE__", |
| TOK.moduleString: "__MODULE__", |
| TOK.functionString: "__FUNCTION__", |
| TOK.prettyFunction: "__PRETTY_FUNCTION__", |
| TOK.shared_: "shared", |
| TOK.immutable_: "immutable", |
| |
| TOK.endOfFile: "End of File", |
| TOK.leftCurly: "{", |
| TOK.rightCurly: "}", |
| TOK.leftParenthesis: "(", |
| TOK.rightParenthesis: ")", |
| TOK.leftBracket: "[", |
| TOK.rightBracket: "]", |
| TOK.semicolon: ";", |
| TOK.colon: ":", |
| TOK.comma: ",", |
| TOK.dot: ".", |
| TOK.xor: "^", |
| TOK.xorAssign: "^=", |
| TOK.assign: "=", |
| TOK.lessThan: "<", |
| TOK.greaterThan: ">", |
| TOK.lessOrEqual: "<=", |
| TOK.greaterOrEqual: ">=", |
| TOK.equal: "==", |
| TOK.notEqual: "!=", |
| TOK.not: "!", |
| TOK.leftShift: "<<", |
| TOK.rightShift: ">>", |
| TOK.unsignedRightShift: ">>>", |
| TOK.add: "+", |
| TOK.min: "-", |
| TOK.mul: "*", |
| TOK.div: "/", |
| TOK.mod: "%", |
| TOK.slice: "..", |
| TOK.dotDotDot: "...", |
| TOK.and: "&", |
| TOK.andAnd: "&&", |
| TOK.or: "|", |
| TOK.orOr: "||", |
| TOK.tilde: "~", |
| TOK.dollar: "$", |
| TOK.plusPlus: "++", |
| TOK.minusMinus: "--", |
| TOK.question: "?", |
| TOK.variable: "var", |
| TOK.addAssign: "+=", |
| TOK.minAssign: "-=", |
| TOK.mulAssign: "*=", |
| TOK.divAssign: "/=", |
| TOK.modAssign: "%=", |
| TOK.leftShiftAssign: "<<=", |
| TOK.rightShiftAssign: ">>=", |
| TOK.unsignedRightShiftAssign: ">>>=", |
| TOK.andAssign: "&=", |
| TOK.orAssign: "|=", |
| TOK.concatenateAssign: "~=", |
| TOK.identity: "is", |
| TOK.notIdentity: "!is", |
| TOK.identifier: "identifier", |
| TOK.at: "@", |
| TOK.pow: "^^", |
| TOK.powAssign: "^^=", |
| TOK.goesTo: "=>", |
| TOK.pound: "#", |
| TOK.arrow: "->", |
| TOK.colonColon: "::", |
| |
| // For debugging |
| TOK.error: "error", |
| TOK.string_: "string", |
| TOK.onScopeExit: "scope(exit)", |
| TOK.onScopeSuccess: "scope(success)", |
| TOK.onScopeFailure: "scope(failure)", |
| |
| // Finish up |
| TOK.reserved: "reserved", |
| TOK.comment: "comment", |
| TOK.int32Literal: "int32v", |
| TOK.uns32Literal: "uns32v", |
| TOK.int64Literal: "int64v", |
| TOK.uns64Literal: "uns64v", |
| TOK.int128Literal: "int128v", |
| TOK.uns128Literal: "uns128v", |
| TOK.float32Literal: "float32v", |
| TOK.float64Literal: "float64v", |
| TOK.float80Literal: "float80v", |
| TOK.imaginary32Literal: "imaginary32v", |
| TOK.imaginary64Literal: "imaginary64v", |
| TOK.imaginary80Literal: "imaginary80v", |
| TOK.charLiteral: "charv", |
| TOK.wcharLiteral: "wcharv", |
| TOK.dcharLiteral: "dcharv", |
| TOK.wchar_tLiteral: "wchar_tv", |
| TOK.endOfLine: "\\n", |
| TOK.whitespace: "whitespace", |
| |
| // C only keywords |
| TOK.inline : "inline", |
| TOK.register : "register", |
| TOK.restrict : "restrict", |
| TOK.signed : "signed", |
| TOK.sizeof_ : "sizeof", |
| TOK.typedef_ : "typedef", |
| TOK.unsigned : "unsigned", |
| TOK.volatile : "volatile", |
| TOK._Alignas : "_Alignas", |
| TOK._Alignof : "_Alignof", |
| TOK._Atomic : "_Atomic", |
| TOK._Bool : "_Bool", |
| TOK._Complex : "_Complex", |
| TOK._Generic : "_Generic", |
| TOK._Imaginary: "_Imaginary", |
| TOK._Noreturn : "_Noreturn", |
| TOK._Static_assert : "_Static_assert", |
| TOK._Thread_local : "_Thread_local", |
| |
| // C only extended keywords |
| TOK._import : "__import", |
| TOK.__cdecl : "__cdecl", |
| TOK.__declspec : "__declspec", |
| TOK.__stdcall : "__stdcall", |
| TOK.__pragma : "__pragma", |
| TOK.__attribute__ : "__attribute__", |
| ]; |
| |
| static assert(() { |
| foreach (s; tochars) |
| assert(s.length); |
| return true; |
| }()); |
| |
| nothrow: |
| |
| int isKeyword() const |
| { |
| foreach (kw; keywords) |
| { |
| if (kw == value) |
| return 1; |
| } |
| return 0; |
| } |
| |
| /**** |
| * Set to contents of ptr[0..length] |
| * Params: |
| * ptr = pointer to string |
| * length = length of string |
| */ |
| void setString(const(char)* ptr, size_t length) |
| { |
| auto s = cast(char*)mem.xmalloc_noscan(length + 1); |
| memcpy(s, ptr, length); |
| s[length] = 0; |
| ustring = s; |
| len = cast(uint)length; |
| postfix = 0; |
| } |
| |
| /**** |
| * Set to contents of buf |
| * Params: |
| * buf = string (not zero terminated) |
| */ |
| void setString(const ref OutBuffer buf) |
| { |
| setString(cast(const(char)*)buf[].ptr, buf.length); |
| } |
| |
| /**** |
| * Set to empty string |
| */ |
| void setString() |
| { |
| ustring = ""; |
| len = 0; |
| postfix = 0; |
| } |
| |
| extern (C++) const(char)* toChars() const |
| { |
| __gshared char[3 + 3 * floatvalue.sizeof + 1] buffer; |
| const(char)* p = &buffer[0]; |
| switch (value) |
| { |
| case TOK.int32Literal: |
| sprintf(&buffer[0], "%d", cast(int)intvalue); |
| break; |
| case TOK.uns32Literal: |
| case TOK.wchar_tLiteral: |
| sprintf(&buffer[0], "%uU", cast(uint)unsvalue); |
| break; |
| case TOK.wcharLiteral: |
| case TOK.dcharLiteral: |
| case TOK.charLiteral: |
| { |
| OutBuffer buf; |
| buf.writeSingleCharLiteral(cast(dchar) intvalue); |
| buf.writeByte('\0'); |
| p = buf.extractSlice().ptr; |
| } |
| break; |
| case TOK.int64Literal: |
| sprintf(&buffer[0], "%lldL", cast(long)intvalue); |
| break; |
| case TOK.uns64Literal: |
| sprintf(&buffer[0], "%lluUL", cast(ulong)unsvalue); |
| break; |
| case TOK.float32Literal: |
| CTFloat.sprint(&buffer[0], 'g', floatvalue); |
| strcat(&buffer[0], "f"); |
| break; |
| case TOK.float64Literal: |
| CTFloat.sprint(&buffer[0], 'g', floatvalue); |
| break; |
| case TOK.float80Literal: |
| CTFloat.sprint(&buffer[0], 'g', floatvalue); |
| strcat(&buffer[0], "L"); |
| break; |
| case TOK.imaginary32Literal: |
| CTFloat.sprint(&buffer[0], 'g', floatvalue); |
| strcat(&buffer[0], "fi"); |
| break; |
| case TOK.imaginary64Literal: |
| CTFloat.sprint(&buffer[0], 'g', floatvalue); |
| strcat(&buffer[0], "i"); |
| break; |
| case TOK.imaginary80Literal: |
| CTFloat.sprint(&buffer[0], 'g', floatvalue); |
| strcat(&buffer[0], "Li"); |
| break; |
| case TOK.string_: |
| { |
| OutBuffer buf; |
| buf.writeByte('"'); |
| for (size_t i = 0; i < len;) |
| { |
| dchar c; |
| utf_decodeChar(ustring[0 .. len], i, c); |
| writeCharLiteral(buf, c); |
| } |
| buf.writeByte('"'); |
| if (postfix) |
| buf.writeByte(postfix); |
| buf.writeByte(0); |
| p = buf.extractSlice().ptr; |
| } |
| break; |
| case TOK.identifier: |
| case TOK.enum_: |
| case TOK.struct_: |
| case TOK.import_: |
| case TOK.wchar_: |
| case TOK.dchar_: |
| case TOK.bool_: |
| case TOK.char_: |
| case TOK.int8: |
| case TOK.uns8: |
| case TOK.int16: |
| case TOK.uns16: |
| case TOK.int32: |
| case TOK.uns32: |
| case TOK.int64: |
| case TOK.uns64: |
| case TOK.int128: |
| case TOK.uns128: |
| case TOK.float32: |
| case TOK.float64: |
| case TOK.float80: |
| case TOK.imaginary32: |
| case TOK.imaginary64: |
| case TOK.imaginary80: |
| case TOK.complex32: |
| case TOK.complex64: |
| case TOK.complex80: |
| case TOK.void_: |
| p = ident.toChars(); |
| break; |
| default: |
| p = toChars(value); |
| break; |
| } |
| return p; |
| } |
| |
| static const(char)* toChars(TOK value) |
| { |
| return toString(value).ptr; |
| } |
| |
| extern (D) static string toString(TOK value) pure nothrow @nogc @safe |
| { |
| return tochars[value]; |
| } |
| } |
| |
| /** |
| * Write a character, using a readable escape sequence if needed |
| * |
| * Useful for printing "" string literals in e.g. error messages, ddoc, or the `.stringof` property |
| * |
| * Params: |
| * buf = buffer to append character in |
| * c = code point to write |
| */ |
| nothrow |
| void writeCharLiteral(ref OutBuffer buf, dchar c) |
| { |
| switch (c) |
| { |
| case '\0': |
| buf.writestring("\\0"); |
| break; |
| case '\n': |
| buf.writestring("\\n"); |
| break; |
| case '\r': |
| buf.writestring("\\r"); |
| break; |
| case '\t': |
| buf.writestring("\\t"); |
| break; |
| case '\b': |
| buf.writestring("\\b"); |
| break; |
| case '\f': |
| buf.writestring("\\f"); |
| break; |
| case '"': |
| case '\\': |
| buf.writeByte('\\'); |
| goto default; |
| default: |
| if (c <= 0xFF) |
| { |
| if (isprint(c)) |
| buf.writeByte(c); |
| else |
| buf.printf("\\x%02x", c); |
| } |
| else if (c <= 0xFFFF) |
| buf.printf("\\u%04x", c); |
| else |
| buf.printf("\\U%08x", c); |
| break; |
| } |
| } |
| |
| unittest |
| { |
| OutBuffer buf; |
| foreach(dchar d; "a\n\r\t\b\f\0\x11\u7233\U00017233"d) |
| { |
| writeCharLiteral(buf, d); |
| } |
| assert(buf.extractSlice() == `a\n\r\t\b\f\0\x11\u7233\U00017233`); |
| } |
| |
| /** |
| * Write a single-quoted character literal |
| * |
| * Useful for printing '' char literals in e.g. error messages, ddoc, or the `.stringof` property |
| * |
| * Params: |
| * buf = buffer to append character in |
| * c = code point to write |
| */ |
| nothrow |
| void writeSingleCharLiteral(ref OutBuffer buf, dchar c) |
| { |
| buf.writeByte('\''); |
| if (c == '\'') |
| buf.writeByte('\\'); |
| |
| if (c == '"') |
| buf.writeByte('"'); |
| else |
| writeCharLiteral(buf, c); |
| |
| buf.writeByte('\''); |
| } |
| |
| unittest |
| { |
| OutBuffer buf; |
| writeSingleCharLiteral(buf, '\''); |
| assert(buf.extractSlice() == `'\''`); |
| buf.reset(); |
| writeSingleCharLiteral(buf, '"'); |
| assert(buf.extractSlice() == `'"'`); |
| buf.reset(); |
| writeSingleCharLiteral(buf, '\n'); |
| assert(buf.extractSlice() == `'\n'`); |
| } |