aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.clang-format274
-rw-r--r--examples/coroutines/aco.c434
-rw-r--r--examples/coroutines/aco.h168
-rw-r--r--lib/commands/commands.c107
-rw-r--r--lib/patterns/match_type.h1
-rw-r--r--lib/patterns/patterns.c715
-rw-r--r--lib/random/chacha.h304
-rw-r--r--lib/random/sysrandom.h2
-rw-r--r--lib/time/time_defs.h31
-rw-r--r--src/ast.c375
-rw-r--r--src/ast.h248
-rw-r--r--src/compile.c2824
-rw-r--r--src/config.h18
-rw-r--r--src/enums.c40
-rw-r--r--src/environment.c824
-rw-r--r--src/environment.h34
-rw-r--r--src/modules.c70
-rw-r--r--src/naming.c101
-rw-r--r--src/parse.c1020
-rw-r--r--src/stdlib/bools.c42
-rw-r--r--src/stdlib/bools.h4
-rw-r--r--src/stdlib/bytes.c98
-rw-r--r--src/stdlib/c_strings.c76
-rw-r--r--src/stdlib/datatypes.h33
-rw-r--r--src/stdlib/enums.c65
-rw-r--r--src/stdlib/enums.h38
-rw-r--r--src/stdlib/files.c114
-rw-r--r--src/stdlib/files.h24
-rw-r--r--src/stdlib/fpconv.c114
-rw-r--r--src/stdlib/functiontype.c13
-rw-r--r--src/stdlib/functiontype.h33
-rw-r--r--src/stdlib/integers.c620
-rw-r--r--src/stdlib/integers.h271
-rw-r--r--src/stdlib/lists.c569
-rw-r--r--src/stdlib/lists.h233
-rw-r--r--src/stdlib/mapmacro.h4
-rw-r--r--src/stdlib/memory.c25
-rw-r--r--src/stdlib/metamethods.c76
-rw-r--r--src/stdlib/metamethods.h4
-rw-r--r--src/stdlib/nums.c214
-rw-r--r--src/stdlib/optionals.c57
-rw-r--r--src/stdlib/optionals.h40
-rw-r--r--src/stdlib/paths.c556
-rw-r--r--src/stdlib/paths.h5
-rw-r--r--src/stdlib/pointers.c58
-rw-r--r--src/stdlib/pointers.h42
-rw-r--r--src/stdlib/powers.h86
-rw-r--r--src/stdlib/print.c181
-rw-r--r--src/stdlib/print.h95
-rw-r--r--src/stdlib/random.h6
-rw-r--r--src/stdlib/simpleparse.c62
-rw-r--r--src/stdlib/simpleparse.h58
-rw-r--r--src/stdlib/siphash-internals.h73
-rw-r--r--src/stdlib/siphash.c10
-rw-r--r--src/stdlib/siphash.h2
-rw-r--r--src/stdlib/stacktrace.c68
-rw-r--r--src/stdlib/stacktrace.h3
-rw-r--r--src/stdlib/stdlib.c370
-rw-r--r--src/stdlib/stdlib.h114
-rw-r--r--src/stdlib/structs.c85
-rw-r--r--src/stdlib/structs.h38
-rw-r--r--src/stdlib/tables.c327
-rw-r--r--src/stdlib/tables.h163
-rw-r--r--src/stdlib/text.c880
-rw-r--r--src/stdlib/text.h44
-rw-r--r--src/stdlib/types.c21
-rw-r--r--src/stdlib/types.h63
-rw-r--r--src/stdlib/util.h44
-rw-r--r--src/structs.c43
-rw-r--r--src/structs.h3
-rw-r--r--src/tomo.c511
-rw-r--r--src/typecheck.c879
-rw-r--r--src/types.c455
-rw-r--r--src/types.h43
74 files changed, 7796 insertions, 7949 deletions
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 00000000..e8555e59
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,274 @@
+---
+Language: Cpp
+AccessModifierOffset: -2
+AlignAfterOpenBracket: Align
+AlignArrayOfStructures: None
+AlignConsecutiveAssignments:
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
+ AlignFunctionPointers: false
+ PadOperators: true
+AlignConsecutiveBitFields:
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
+ AlignFunctionPointers: false
+ PadOperators: false
+AlignConsecutiveDeclarations:
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
+ AlignFunctionPointers: false
+ PadOperators: false
+AlignConsecutiveMacros:
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
+ AlignFunctionPointers: false
+ PadOperators: false
+AlignConsecutiveShortCaseStatements:
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCaseArrows: false
+ AlignCaseColons: false
+AlignConsecutiveTableGenBreakingDAGArgColons:
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
+ AlignFunctionPointers: false
+ PadOperators: false
+AlignConsecutiveTableGenCondOperatorColons:
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
+ AlignFunctionPointers: false
+ PadOperators: false
+AlignConsecutiveTableGenDefinitionColons:
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
+ AlignFunctionPointers: false
+ PadOperators: false
+AlignEscapedNewlines: Right
+AlignOperands: Align
+AlignTrailingComments:
+ Kind: Always
+ OverEmptyLines: 0
+AllowAllArgumentsOnNextLine: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowBreakBeforeNoexceptSpecifier: Never
+AllowShortBlocksOnASingleLine: Never
+AllowShortCaseExpressionOnASingleLine: true
+AllowShortCaseLabelsOnASingleLine: true
+AllowShortCompoundRequirementOnASingleLine: true
+AllowShortEnumsOnASingleLine: true
+AllowShortFunctionsOnASingleLine: All
+AllowShortIfStatementsOnASingleLine: AllIfsAndElse
+AllowShortLambdasOnASingleLine: All
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakBeforeMultilineStrings: false
+AttributeMacros:
+ - __capability
+BinPackArguments: true
+BinPackParameters: true
+BitFieldColonSpacing: Both
+BraceWrapping:
+ AfterCaseLabel: false
+ AfterClass: false
+ AfterControlStatement: Never
+ AfterEnum: false
+ AfterExternBlock: false
+ AfterFunction: false
+ AfterNamespace: false
+ AfterObjCDeclaration: false
+ AfterStruct: false
+ AfterUnion: false
+ BeforeCatch: false
+ BeforeElse: false
+ BeforeLambdaBody: false
+ BeforeWhile: false
+ IndentBraces: false
+ SplitEmptyFunction: true
+ SplitEmptyRecord: true
+ SplitEmptyNamespace: true
+BreakAdjacentStringLiterals: true
+BreakAfterAttributes: Leave
+BreakAfterJavaFieldAnnotations: false
+BreakAfterReturnType: None
+BreakArrays: true
+BreakBeforeBinaryOperators: NonAssignment
+BreakBeforeConceptDeclarations: Always
+BreakBeforeBraces: Attach
+BreakBeforeInlineASMColon: OnlyMultiline
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializers: BeforeColon
+BreakFunctionDefinitionParameters: false
+BreakInheritanceList: BeforeColon
+BreakStringLiterals: true
+BreakTemplateDeclarations: MultiLine
+ColumnLimit: 120
+CommentPragmas: '^ IWYU pragma:'
+CompactNamespaces: false
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: true
+DerivePointerAlignment: false
+DisableFormat: false
+EmptyLineAfterAccessModifier: Never
+EmptyLineBeforeAccessModifier: LogicalBlock
+ExperimentalAutoDetectBinPacking: false
+FixNamespaceComments: true
+ForEachMacros:
+ - foreach
+ - Q_FOREACH
+ - BOOST_FOREACH
+IfMacros:
+ - KJ_IF_MAYBE
+IncludeBlocks: Preserve
+IncludeCategories:
+ - Regex: '^"(llvm|llvm-c|clang|clang-c)/'
+ Priority: 2
+ SortPriority: 0
+ CaseSensitive: false
+ - Regex: '^(<|"(gtest|gmock|isl|json)/)'
+ Priority: 3
+ SortPriority: 0
+ CaseSensitive: false
+ - Regex: '.*'
+ Priority: 1
+ SortPriority: 0
+ CaseSensitive: false
+IncludeIsMainRegex: '(Test)?$'
+IncludeIsMainSourceRegex: ''
+IndentAccessModifiers: false
+IndentCaseBlocks: false
+IndentCaseLabels: false
+IndentExternBlock: AfterExternBlock
+IndentGotoLabels: true
+IndentPPDirectives: None
+IndentRequiresClause: true
+IndentWidth: 4
+IndentWrappedFunctionNames: false
+InsertBraces: false
+InsertNewlineAtEOF: false
+InsertTrailingCommas: None
+IntegerLiteralSeparator:
+ Binary: 0
+ BinaryMinDigits: 0
+ Decimal: 0
+ DecimalMinDigits: 0
+ Hex: 0
+ HexMinDigits: 0
+JavaScriptQuotes: Leave
+JavaScriptWrapImports: true
+KeepEmptyLines:
+ AtEndOfFile: false
+ AtStartOfBlock: true
+ AtStartOfFile: true
+LambdaBodyIndentation: Signature
+LineEnding: DeriveLF
+MacroBlockBegin: ''
+MacroBlockEnd: ''
+MainIncludeChar: Quote
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCBinPackProtocolList: Auto
+ObjCBlockIndentWidth: 2
+ObjCBreakBeforeNestedBlockParam: true
+ObjCSpaceAfterProperty: false
+ObjCSpaceBeforeProtocolList: true
+PackConstructorInitializers: BinPack
+PenaltyBreakAssignment: 2
+PenaltyBreakBeforeFirstCallParameter: 19
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakOpenParenthesis: 0
+PenaltyBreakScopeResolution: 500
+PenaltyBreakString: 1000
+PenaltyBreakTemplateDeclaration: 10
+PenaltyExcessCharacter: 1000000
+PenaltyIndentedWhitespace: 0
+PenaltyReturnTypeOnItsOwnLine: 60
+PointerAlignment: Right
+PPIndentWidth: -1
+QualifierAlignment: Leave
+ReferenceAlignment: Pointer
+ReflowComments: true
+RemoveBracesLLVM: false
+RemoveParentheses: Leave
+RemoveSemicolon: false
+RequiresClausePosition: OwnLine
+RequiresExpressionIndentation: OuterScope
+SeparateDefinitionBlocks: Leave
+ShortNamespaceLines: 1
+SkipMacroDefinitionBody: false
+SortIncludes: CaseSensitive
+SortJavaStaticImport: Before
+SortUsingDeclarations: LexicographicNumeric
+SpaceAfterCStyleCast: false
+SpaceAfterLogicalNot: false
+SpaceAfterTemplateKeyword: true
+SpaceAroundPointerQualifiers: Default
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeCaseColon: false
+SpaceBeforeCpp11BracedList: false
+SpaceBeforeCtorInitializerColon: true
+SpaceBeforeInheritanceColon: true
+SpaceBeforeJsonColon: false
+SpaceBeforeParens: ControlStatements
+SpaceBeforeParensOptions:
+ AfterControlStatements: true
+ AfterForeachMacros: true
+ AfterFunctionDefinitionName: false
+ AfterFunctionDeclarationName: false
+ AfterIfMacros: true
+ AfterOverloadedOperator: false
+ AfterPlacementOperator: true
+ AfterRequiresInClause: false
+ AfterRequiresInExpression: false
+ BeforeNonEmptyParentheses: false
+SpaceBeforeRangeBasedForLoopColon: true
+SpaceBeforeSquareBrackets: false
+SpaceInEmptyBlock: false
+SpacesBeforeTrailingComments: 1
+SpacesInAngles: Never
+SpacesInContainerLiterals: true
+SpacesInLineCommentPrefix:
+ Minimum: 1
+ Maximum: -1
+SpacesInParens: Never
+SpacesInParensOptions:
+ ExceptDoubleParentheses: false
+ InCStyleCasts: false
+ InConditionalStatements: false
+ InEmptyParentheses: false
+ Other: false
+SpacesInSquareBrackets: false
+Standard: Latest
+StatementAttributeLikeMacros:
+ - Q_EMIT
+StatementMacros:
+ - Q_UNUSED
+ - QT_REQUIRE_VERSION
+TableGenBreakInsideDAGArg: DontBreak
+TabWidth: 4
+UseTab: Never
+VerilogBreakBetweenInstancePorts: true
+WhitespaceSensitiveMacros:
+ - BOOST_PP_STRINGIZE
+ - CF_SWIFT_NAME
+ - NS_SWIFT_NAME
+ - PP_STRINGIZE
+ - STRINGIZE
+...
+
diff --git a/examples/coroutines/aco.c b/examples/coroutines/aco.c
index 6057466f..258efe28 100644
--- a/examples/coroutines/aco.c
+++ b/examples/coroutines/aco.c
@@ -16,193 +16,194 @@
#define _GNU_SOURCE
#include "aco.h"
-#include <stdio.h>
#include <stdint.h>
+#include <stdio.h>
#ifndef public
-#define public __attribute__ ((visibility ("default")))
+#define public __attribute__((visibility("default")))
#endif
-#define aco_size_t_safe_add_assert(a,b) aco_assert((a)+(b) >= (a))
+#define aco_size_t_safe_add_assert(a, b) aco_assert((a) + (b) >= (a))
-static void aco_default_protector_last_word(void*);
+static void aco_default_protector_last_word(void *);
-void* (*aco_alloc_fn)(size_t) = malloc;
-void (*aco_dealloc_fn)(void*) = free;
+void *(*aco_alloc_fn)(size_t) = malloc;
+void (*aco_dealloc_fn)(void *) = free;
-#define aco_alloc(size) ({ \
- void *_ptr = aco_alloc_fn(size); \
- if (aco_unlikely((_ptr) == NULL)) { \
- fprintf(stderr, "Aborting: failed to allocate memory: %s:%d:%s\n", \
- __FILE__, __LINE__, __PRETTY_FUNCTION__); \
- abort(); \
- } \
- _ptr; \
-})
+#define aco_alloc(size) \
+ ({ \
+ void *_ptr = aco_alloc_fn(size); \
+ if (aco_unlikely((_ptr) == NULL)) { \
+ fprintf(stderr, "Aborting: failed to allocate memory: %s:%d:%s\n", __FILE__, __LINE__, \
+ __PRETTY_FUNCTION__); \
+ abort(); \
+ } \
+ _ptr; \
+ })
// aco's Global Thread Local Storage variable `co`
-public __thread aco_t* aco_gtls_co;
+public
+__thread aco_t *aco_gtls_co;
static __thread aco_cofuncp_t aco_gtls_last_word_fp = aco_default_protector_last_word;
#ifdef __i386__
- static __thread void* aco_gtls_fpucw_mxcsr[2];
-#elif __x86_64__
- static __thread void* aco_gtls_fpucw_mxcsr[1];
+static __thread void *aco_gtls_fpucw_mxcsr[2];
+#elif __x86_64__
+static __thread void *aco_gtls_fpucw_mxcsr[1];
#else
- #error "platform not supporteded yet"
+#error "platform not supporteded yet"
#endif
-public void aco_runtime_test(void) {
+public
+void aco_runtime_test(void) {
#ifdef __i386__
- _Static_assert(sizeof(void*) == 4, "require 'sizeof(void*) == 4'");
-#elif __x86_64__
- _Static_assert(sizeof(void*) == 8, "require 'sizeof(void*) == 8'");
+ _Static_assert(sizeof(void *) == 4, "require 'sizeof(void*) == 4'");
+#elif __x86_64__
+ _Static_assert(sizeof(void *) == 8, "require 'sizeof(void*) == 8'");
_Static_assert(sizeof(__uint128_t) == 16, "require 'sizeof(__uint128_t) == 16'");
#else
- #error "platform not supporteded yet"
+#error "platform not supporteded yet"
#endif
_Static_assert(sizeof(int) >= 4, "require 'sizeof(int) >= 4'");
aco_assert(sizeof(int) >= 4);
- _Static_assert(sizeof(int) <= sizeof(size_t),
- "require 'sizeof(int) <= sizeof(size_t)'");
+ _Static_assert(sizeof(int) <= sizeof(size_t), "require 'sizeof(int) <= sizeof(size_t)'");
aco_assert(sizeof(int) <= sizeof(size_t));
}
#ifdef __x86_64__
static inline void aco_fast_memcpy(void *dst, const void *src, size_t sz) {
- if (((uintptr_t)src & 0x0f) != 0
- || ((uintptr_t)dst & 0x0f) != 0
- || (sz & 0x0f) != 0x08
- || (sz >> 4) > 8) {
+ if (((uintptr_t)src & 0x0f) != 0 || ((uintptr_t)dst & 0x0f) != 0 || (sz & 0x0f) != 0x08 || (sz >> 4) > 8) {
memcpy(dst, src, sz);
return;
}
- __uint128_t xmm0,xmm1,xmm2,xmm3,xmm4,xmm5,xmm6,xmm7;
+ __uint128_t xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7;
switch (sz >> 4) {
- case 0:
- break;
- case 1:
- xmm0 = *((__uint128_t*)src + 0);
- *((__uint128_t*)dst + 0) = xmm0;
- break;
- case 2:
- xmm0 = *((__uint128_t*)src + 0);
- xmm1 = *((__uint128_t*)src + 1);
- *((__uint128_t*)dst + 0) = xmm0;
- *((__uint128_t*)dst + 1) = xmm1;
- break;
- case 3:
- xmm0 = *((__uint128_t*)src + 0);
- xmm1 = *((__uint128_t*)src + 1);
- xmm2 = *((__uint128_t*)src + 2);
- *((__uint128_t*)dst + 0) = xmm0;
- *((__uint128_t*)dst + 1) = xmm1;
- *((__uint128_t*)dst + 2) = xmm2;
- break;
- case 4:
- xmm0 = *((__uint128_t*)src + 0);
- xmm1 = *((__uint128_t*)src + 1);
- xmm2 = *((__uint128_t*)src + 2);
- xmm3 = *((__uint128_t*)src + 3);
- *((__uint128_t*)dst + 0) = xmm0;
- *((__uint128_t*)dst + 1) = xmm1;
- *((__uint128_t*)dst + 2) = xmm2;
- *((__uint128_t*)dst + 3) = xmm3;
- break;
- case 5:
- xmm0 = *((__uint128_t*)src + 0);
- xmm1 = *((__uint128_t*)src + 1);
- xmm2 = *((__uint128_t*)src + 2);
- xmm3 = *((__uint128_t*)src + 3);
- xmm4 = *((__uint128_t*)src + 4);
- *((__uint128_t*)dst + 0) = xmm0;
- *((__uint128_t*)dst + 1) = xmm1;
- *((__uint128_t*)dst + 2) = xmm2;
- *((__uint128_t*)dst + 3) = xmm3;
- *((__uint128_t*)dst + 4) = xmm4;
- break;
- case 6:
- xmm0 = *((__uint128_t*)src + 0);
- xmm1 = *((__uint128_t*)src + 1);
- xmm2 = *((__uint128_t*)src + 2);
- xmm3 = *((__uint128_t*)src + 3);
- xmm4 = *((__uint128_t*)src + 4);
- xmm5 = *((__uint128_t*)src + 5);
- *((__uint128_t*)dst + 0) = xmm0;
- *((__uint128_t*)dst + 1) = xmm1;
- *((__uint128_t*)dst + 2) = xmm2;
- *((__uint128_t*)dst + 3) = xmm3;
- *((__uint128_t*)dst + 4) = xmm4;
- *((__uint128_t*)dst + 5) = xmm5;
- break;
- case 7:
- xmm0 = *((__uint128_t*)src + 0);
- xmm1 = *((__uint128_t*)src + 1);
- xmm2 = *((__uint128_t*)src + 2);
- xmm3 = *((__uint128_t*)src + 3);
- xmm4 = *((__uint128_t*)src + 4);
- xmm5 = *((__uint128_t*)src + 5);
- xmm6 = *((__uint128_t*)src + 6);
- *((__uint128_t*)dst + 0) = xmm0;
- *((__uint128_t*)dst + 1) = xmm1;
- *((__uint128_t*)dst + 2) = xmm2;
- *((__uint128_t*)dst + 3) = xmm3;
- *((__uint128_t*)dst + 4) = xmm4;
- *((__uint128_t*)dst + 5) = xmm5;
- *((__uint128_t*)dst + 6) = xmm6;
- break;
- case 8:
- xmm0 = *((__uint128_t*)src + 0);
- xmm1 = *((__uint128_t*)src + 1);
- xmm2 = *((__uint128_t*)src + 2);
- xmm3 = *((__uint128_t*)src + 3);
- xmm4 = *((__uint128_t*)src + 4);
- xmm5 = *((__uint128_t*)src + 5);
- xmm6 = *((__uint128_t*)src + 6);
- xmm7 = *((__uint128_t*)src + 7);
- *((__uint128_t*)dst + 0) = xmm0;
- *((__uint128_t*)dst + 1) = xmm1;
- *((__uint128_t*)dst + 2) = xmm2;
- *((__uint128_t*)dst + 3) = xmm3;
- *((__uint128_t*)dst + 4) = xmm4;
- *((__uint128_t*)dst + 5) = xmm5;
- *((__uint128_t*)dst + 6) = xmm6;
- *((__uint128_t*)dst + 7) = xmm7;
- break;
+ case 0: break;
+ case 1:
+ xmm0 = *((__uint128_t *)src + 0);
+ *((__uint128_t *)dst + 0) = xmm0;
+ break;
+ case 2:
+ xmm0 = *((__uint128_t *)src + 0);
+ xmm1 = *((__uint128_t *)src + 1);
+ *((__uint128_t *)dst + 0) = xmm0;
+ *((__uint128_t *)dst + 1) = xmm1;
+ break;
+ case 3:
+ xmm0 = *((__uint128_t *)src + 0);
+ xmm1 = *((__uint128_t *)src + 1);
+ xmm2 = *((__uint128_t *)src + 2);
+ *((__uint128_t *)dst + 0) = xmm0;
+ *((__uint128_t *)dst + 1) = xmm1;
+ *((__uint128_t *)dst + 2) = xmm2;
+ break;
+ case 4:
+ xmm0 = *((__uint128_t *)src + 0);
+ xmm1 = *((__uint128_t *)src + 1);
+ xmm2 = *((__uint128_t *)src + 2);
+ xmm3 = *((__uint128_t *)src + 3);
+ *((__uint128_t *)dst + 0) = xmm0;
+ *((__uint128_t *)dst + 1) = xmm1;
+ *((__uint128_t *)dst + 2) = xmm2;
+ *((__uint128_t *)dst + 3) = xmm3;
+ break;
+ case 5:
+ xmm0 = *((__uint128_t *)src + 0);
+ xmm1 = *((__uint128_t *)src + 1);
+ xmm2 = *((__uint128_t *)src + 2);
+ xmm3 = *((__uint128_t *)src + 3);
+ xmm4 = *((__uint128_t *)src + 4);
+ *((__uint128_t *)dst + 0) = xmm0;
+ *((__uint128_t *)dst + 1) = xmm1;
+ *((__uint128_t *)dst + 2) = xmm2;
+ *((__uint128_t *)dst + 3) = xmm3;
+ *((__uint128_t *)dst + 4) = xmm4;
+ break;
+ case 6:
+ xmm0 = *((__uint128_t *)src + 0);
+ xmm1 = *((__uint128_t *)src + 1);
+ xmm2 = *((__uint128_t *)src + 2);
+ xmm3 = *((__uint128_t *)src + 3);
+ xmm4 = *((__uint128_t *)src + 4);
+ xmm5 = *((__uint128_t *)src + 5);
+ *((__uint128_t *)dst + 0) = xmm0;
+ *((__uint128_t *)dst + 1) = xmm1;
+ *((__uint128_t *)dst + 2) = xmm2;
+ *((__uint128_t *)dst + 3) = xmm3;
+ *((__uint128_t *)dst + 4) = xmm4;
+ *((__uint128_t *)dst + 5) = xmm5;
+ break;
+ case 7:
+ xmm0 = *((__uint128_t *)src + 0);
+ xmm1 = *((__uint128_t *)src + 1);
+ xmm2 = *((__uint128_t *)src + 2);
+ xmm3 = *((__uint128_t *)src + 3);
+ xmm4 = *((__uint128_t *)src + 4);
+ xmm5 = *((__uint128_t *)src + 5);
+ xmm6 = *((__uint128_t *)src + 6);
+ *((__uint128_t *)dst + 0) = xmm0;
+ *((__uint128_t *)dst + 1) = xmm1;
+ *((__uint128_t *)dst + 2) = xmm2;
+ *((__uint128_t *)dst + 3) = xmm3;
+ *((__uint128_t *)dst + 4) = xmm4;
+ *((__uint128_t *)dst + 5) = xmm5;
+ *((__uint128_t *)dst + 6) = xmm6;
+ break;
+ case 8:
+ xmm0 = *((__uint128_t *)src + 0);
+ xmm1 = *((__uint128_t *)src + 1);
+ xmm2 = *((__uint128_t *)src + 2);
+ xmm3 = *((__uint128_t *)src + 3);
+ xmm4 = *((__uint128_t *)src + 4);
+ xmm5 = *((__uint128_t *)src + 5);
+ xmm6 = *((__uint128_t *)src + 6);
+ xmm7 = *((__uint128_t *)src + 7);
+ *((__uint128_t *)dst + 0) = xmm0;
+ *((__uint128_t *)dst + 1) = xmm1;
+ *((__uint128_t *)dst + 2) = xmm2;
+ *((__uint128_t *)dst + 3) = xmm3;
+ *((__uint128_t *)dst + 4) = xmm4;
+ *((__uint128_t *)dst + 5) = xmm5;
+ *((__uint128_t *)dst + 6) = xmm6;
+ *((__uint128_t *)dst + 7) = xmm7;
+ break;
}
- *((uint64_t*)((uintptr_t)dst + sz - 8)) = *((uint64_t*)((uintptr_t)src + sz - 8));
+ *((uint64_t *)((uintptr_t)dst + sz - 8)) = *((uint64_t *)((uintptr_t)src + sz - 8));
}
#endif
-void aco_default_protector_last_word(void*_) {
- aco_t* co = aco_get_co();
+void aco_default_protector_last_word(void *_) {
+ aco_t *co = aco_get_co();
// do some log about the offending `co`
- fprintf(stderr,"error: aco_default_protector_last_word triggered\n");
- fprintf(stderr, "error: co:%p should call `aco_exit()` instead of direct "
- "`return` in co_fp:%p to finish its execution\n", co, (void*)co->fp);
+ fprintf(stderr, "error: aco_default_protector_last_word triggered\n");
+ fprintf(stderr,
+ "error: co:%p should call `aco_exit()` instead of direct "
+ "`return` in co_fp:%p to finish its execution\n",
+ co, (void *)co->fp);
aco_assert(0);
}
-public void aco_set_allocator(void* (*alloc)(size_t), void (*dealloc)(void*))
-{
+public
+void aco_set_allocator(void *(*alloc)(size_t), void (*dealloc)(void *)) {
aco_alloc_fn = alloc;
aco_dealloc_fn = dealloc;
}
-public void aco_thread_init(aco_cofuncp_t last_word_co_fp) {
+public
+void aco_thread_init(aco_cofuncp_t last_word_co_fp) {
aco_save_fpucw_mxcsr(aco_gtls_fpucw_mxcsr);
- if ((void*)last_word_co_fp != NULL)
- aco_gtls_last_word_fp = last_word_co_fp;
+ if ((void *)last_word_co_fp != NULL) aco_gtls_last_word_fp = last_word_co_fp;
}
// This function `aco_funcp_protector` should never be
// called. If it's been called, that means the offending
// `co` didn't call aco_exit(co) instead of `return` to
// finish its execution.
-public void aco_funcp_protector(void) {
- if ((void*)(aco_gtls_last_word_fp) != NULL) {
+public
+void aco_funcp_protector(void) {
+ if ((void *)(aco_gtls_last_word_fp) != NULL) {
aco_gtls_last_word_fp(NULL);
} else {
aco_default_protector_last_word(NULL);
@@ -210,11 +211,11 @@ public void aco_funcp_protector(void) {
aco_assert(0);
}
-public aco_shared_stack_t* aco_shared_stack_new(size_t sz) {
- return aco_shared_stack_new2(sz, 1);
-}
+public
+aco_shared_stack_t *aco_shared_stack_new(size_t sz) { return aco_shared_stack_new2(sz, 1); }
-public aco_shared_stack_t* aco_shared_stack_new2(size_t sz, bool guard_page_enabled) {
+public
+aco_shared_stack_t *aco_shared_stack_new2(size_t sz, bool guard_page_enabled) {
if (sz == 0) {
sz = 1024 * 1024 * 2;
}
@@ -253,52 +254,48 @@ public aco_shared_stack_t* aco_shared_stack_new2(size_t sz, bool guard_page_enab
}
}
- aco_shared_stack_t* p = aco_alloc(sizeof(aco_shared_stack_t));
+ aco_shared_stack_t *p = aco_alloc(sizeof(aco_shared_stack_t));
memset(p, 0, sizeof(aco_shared_stack_t));
if (guard_page_enabled) {
- p->real_ptr = mmap(
- NULL, sz, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0
- );
+ p->real_ptr = mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (aco_unlikely(p->real_ptr == MAP_FAILED)) {
- fprintf(stderr, "Aborting: failed to allocate memory: %s:%d:%s\n",
- __FILE__, __LINE__, __PRETTY_FUNCTION__);
+ fprintf(stderr, "Aborting: failed to allocate memory: %s:%d:%s\n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
abort();
}
p->guard_page_enabled = true;
aco_assert(0 == mprotect(p->real_ptr, u_pgsz, PROT_READ));
- p->ptr = (void*)(((uintptr_t)p->real_ptr) + u_pgsz);
+ p->ptr = (void *)(((uintptr_t)p->real_ptr) + u_pgsz);
p->real_sz = sz;
aco_assert(sz >= (u_pgsz << 1));
p->sz = sz - u_pgsz;
} else {
- //p->guard_page_enabled = 0;
+ // p->guard_page_enabled = 0;
p->sz = sz;
p->ptr = aco_alloc(sz);
}
p->owner = NULL;
#ifdef ACO_USE_VALGRIND
- p->valgrind_stk_id = VALGRIND_STACK_REGISTER(
- p->ptr, (void*)((uintptr_t)p->ptr + p->sz)
- );
+ p->valgrind_stk_id = VALGRIND_STACK_REGISTER(p->ptr, (void *)((uintptr_t)p->ptr + p->sz));
#endif
#if defined(__i386__) || defined(__x86_64__)
- uintptr_t u_p = (uintptr_t)(p->sz - (sizeof(void*) << 1) + (uintptr_t)p->ptr);
+ uintptr_t u_p = (uintptr_t)(p->sz - (sizeof(void *) << 1) + (uintptr_t)p->ptr);
u_p = (u_p >> 4) << 4;
- p->align_highptr = (void*)u_p;
- p->align_retptr = (void*)(u_p - sizeof(void*));
- *((void**)(p->align_retptr)) = (void*)(aco_funcp_protector_asm);
- aco_assert(p->sz > (16 + (sizeof(void*) << 1) + sizeof(void*)));
- p->align_limit = p->sz - 16 - (sizeof(void*) << 1);
+ p->align_highptr = (void *)u_p;
+ p->align_retptr = (void *)(u_p - sizeof(void *));
+ *((void **)(p->align_retptr)) = (void *)(aco_funcp_protector_asm);
+ aco_assert(p->sz > (16 + (sizeof(void *) << 1) + sizeof(void *)));
+ p->align_limit = p->sz - 16 - (sizeof(void *) << 1);
#else
- #error "platform not supporteded yet"
+#error "platform not supporteded yet"
#endif
return p;
}
-public void aco_shared_stack_destroy(aco_shared_stack_t* sstk) {
+public
+void aco_shared_stack_destroy(aco_shared_stack_t *sstk) {
aco_assert(sstk != NULL && sstk->ptr != NULL);
#ifdef ACO_USE_VALGRIND
VALGRIND_STACK_DEREGISTER(sstk->valgrind_stk_id);
@@ -314,11 +311,10 @@ public void aco_shared_stack_destroy(aco_shared_stack_t* sstk) {
if (aco_dealloc_fn != NULL) aco_dealloc_fn(sstk);
}
-public aco_t* aco_create(
- aco_t* main_co, aco_shared_stack_t* shared_stack,
- size_t saved_stack_sz, aco_cofuncp_t fp, void* arg
-) {
- aco_t* p = aco_alloc(sizeof(aco_t));
+public
+aco_t *aco_create(aco_t *main_co, aco_shared_stack_t *shared_stack, size_t saved_stack_sz, aco_cofuncp_t fp,
+ void *arg) {
+ aco_t *p = aco_alloc(sizeof(aco_t));
memset(p, 0, sizeof(aco_t));
if (main_co != NULL) { // non-main co
@@ -327,21 +323,21 @@ public aco_t* aco_create(
#ifdef __i386__
// POSIX.1-2008 (IEEE Std 1003.1-2008) - General Information - Data Types - Pointer Types
// http://pubs.opengroup.org/onlinepubs/9699919799.2008edition/functions/V2_chap02.html#tag_15_12_03
- p->reg[ACO_REG_IDX_RETADDR] = (void*)fp;
+ p->reg[ACO_REG_IDX_RETADDR] = (void *)fp;
// push retaddr
p->reg[ACO_REG_IDX_SP] = p->shared_stack->align_retptr;
- #ifndef ACO_CONFIG_SHARE_FPU_MXCSR_ENV
- p->reg[ACO_REG_IDX_FPU] = aco_gtls_fpucw_mxcsr[0];
- p->reg[ACO_REG_IDX_FPU + 1] = aco_gtls_fpucw_mxcsr[1];
- #endif
-#elif __x86_64__
- p->reg[ACO_REG_IDX_RETADDR] = (void*)fp;
+#ifndef ACO_CONFIG_SHARE_FPU_MXCSR_ENV
+ p->reg[ACO_REG_IDX_FPU] = aco_gtls_fpucw_mxcsr[0];
+ p->reg[ACO_REG_IDX_FPU + 1] = aco_gtls_fpucw_mxcsr[1];
+#endif
+#elif __x86_64__
+ p->reg[ACO_REG_IDX_RETADDR] = (void *)fp;
p->reg[ACO_REG_IDX_SP] = p->shared_stack->align_retptr;
- #ifndef ACO_CONFIG_SHARE_FPU_MXCSR_ENV
- p->reg[ACO_REG_IDX_FPU] = aco_gtls_fpucw_mxcsr[0];
- #endif
+#ifndef ACO_CONFIG_SHARE_FPU_MXCSR_ENV
+ p->reg[ACO_REG_IDX_FPU] = aco_gtls_fpucw_mxcsr[0];
+#endif
#else
- #error "platform not supporteded yet"
+#error "platform not supporteded yet"
#endif
p->main_co = main_co;
p->arg = arg;
@@ -354,7 +350,7 @@ public aco_t* aco_create(
#if defined(__i386__) || defined(__x86_64__)
p->saved_stack.valid_sz = 0;
#else
- #error "platform not supporteded yet"
+#error "platform not supporteded yet"
#endif
return p;
} else { // main co
@@ -368,35 +364,20 @@ public aco_t* aco_create(
aco_assert(0);
}
-public aco_attr_no_asan
-void aco_resume(aco_t* resume_co) {
- aco_assert(resume_co != NULL && resume_co->main_co != NULL
- && !resume_co->is_finished
- );
+public
+aco_attr_no_asan void aco_resume(aco_t *resume_co) {
+ aco_assert(resume_co != NULL && resume_co->main_co != NULL && !resume_co->is_finished);
if (resume_co->shared_stack->owner != resume_co) {
if (resume_co->shared_stack->owner != NULL) {
- aco_t* owner_co = resume_co->shared_stack->owner;
+ aco_t *owner_co = resume_co->shared_stack->owner;
aco_assert(owner_co->shared_stack == resume_co->shared_stack);
#if defined(__i386__) || defined(__x86_64__)
- aco_assert(
- (
- (uintptr_t)(owner_co->shared_stack->align_retptr)
- >=
- (uintptr_t)(owner_co->reg[ACO_REG_IDX_SP])
- )
- &&
- (
- (uintptr_t)(owner_co->shared_stack->align_highptr)
- -
- (uintptr_t)(owner_co->shared_stack->align_limit)
- <=
- (uintptr_t)(owner_co->reg[ACO_REG_IDX_SP])
- )
- );
+ aco_assert(((uintptr_t)(owner_co->shared_stack->align_retptr) >= (uintptr_t)(owner_co->reg[ACO_REG_IDX_SP]))
+ && ((uintptr_t)(owner_co->shared_stack->align_highptr)
+ - (uintptr_t)(owner_co->shared_stack->align_limit)
+ <= (uintptr_t)(owner_co->reg[ACO_REG_IDX_SP])));
owner_co->saved_stack.valid_sz =
- (uintptr_t)(owner_co->shared_stack->align_retptr)
- -
- (uintptr_t)(owner_co->reg[ACO_REG_IDX_SP]);
+ (uintptr_t)(owner_co->shared_stack->align_retptr) - (uintptr_t)(owner_co->reg[ACO_REG_IDX_SP]);
if (owner_co->saved_stack.sz < owner_co->saved_stack.valid_sz) {
if (aco_dealloc_fn != NULL) aco_dealloc_fn(owner_co->saved_stack.ptr);
owner_co->saved_stack.ptr = NULL;
@@ -412,19 +393,12 @@ void aco_resume(aco_t* resume_co) {
// TODO: optimize the performance penalty of memcpy function call
// for very short memory span
if (owner_co->saved_stack.valid_sz > 0) {
- #ifdef __x86_64__
- aco_fast_memcpy(
- owner_co->saved_stack.ptr,
- owner_co->reg[ACO_REG_IDX_SP],
- owner_co->saved_stack.valid_sz
- );
- #else
- memcpy(
- owner_co->saved_stack.ptr,
- owner_co->reg[ACO_REG_IDX_SP],
- owner_co->saved_stack.valid_sz
- );
- #endif
+#ifdef __x86_64__
+ aco_fast_memcpy(owner_co->saved_stack.ptr, owner_co->reg[ACO_REG_IDX_SP],
+ owner_co->saved_stack.valid_sz);
+#else
+ memcpy(owner_co->saved_stack.ptr, owner_co->reg[ACO_REG_IDX_SP], owner_co->saved_stack.valid_sz);
+#endif
owner_co->saved_stack.ct_save++;
}
if (owner_co->saved_stack.valid_sz > owner_co->saved_stack.max_cpsz) {
@@ -433,36 +407,30 @@ void aco_resume(aco_t* resume_co) {
owner_co->shared_stack->owner = NULL;
owner_co->shared_stack->align_validsz = 0;
#else
- #error "platform not supporteded yet"
+#error "platform not supporteded yet"
#endif
}
aco_assert(resume_co->shared_stack->owner == NULL);
#if defined(__i386__) || defined(__x86_64__)
- aco_assert(
- resume_co->saved_stack.valid_sz
- <=
- resume_co->shared_stack->align_limit - sizeof(void*)
- );
+ aco_assert(resume_co->saved_stack.valid_sz <= resume_co->shared_stack->align_limit - sizeof(void *));
// TODO: optimize the performance penalty of memcpy function call
// for very short memory span
if (resume_co->saved_stack.valid_sz > 0) {
- void *dst = (void*)(
- (uintptr_t)(resume_co->shared_stack->align_retptr)
- - resume_co->saved_stack.valid_sz);
- #ifdef __x86_64__
+ void *dst = (void *)((uintptr_t)(resume_co->shared_stack->align_retptr) - resume_co->saved_stack.valid_sz);
+#ifdef __x86_64__
aco_fast_memcpy(dst, resume_co->saved_stack.ptr, resume_co->saved_stack.valid_sz);
- #else
+#else
memcpy(dst, resume_co->saved_stack.ptr, resume_co->saved_stack.valid_sz);
- #endif
+#endif
resume_co->saved_stack.ct_restore++;
}
if (resume_co->saved_stack.valid_sz > resume_co->saved_stack.max_cpsz) {
resume_co->saved_stack.max_cpsz = resume_co->saved_stack.valid_sz;
}
- resume_co->shared_stack->align_validsz = resume_co->saved_stack.valid_sz + sizeof(void*);
+ resume_co->shared_stack->align_validsz = resume_co->saved_stack.valid_sz + sizeof(void *);
resume_co->shared_stack->owner = resume_co;
#else
- #error "platform not supporteded yet"
+#error "platform not supporteded yet"
#endif
}
aco_gtls_co = resume_co;
@@ -470,7 +438,8 @@ void aco_resume(aco_t* resume_co) {
aco_gtls_co = resume_co->main_co;
}
-public void aco_destroy(aco_t* co) {
+public
+void aco_destroy(aco_t *co) {
aco_assertptr(co);
if (aco_is_main_co(co)) {
if (aco_dealloc_fn != NULL) aco_dealloc_fn(co);
@@ -479,14 +448,11 @@ public void aco_destroy(aco_t* co) {
co->shared_stack->owner = NULL;
co->shared_stack->align_validsz = 0;
}
- if (aco_dealloc_fn != NULL)
- aco_dealloc_fn(co->saved_stack.ptr);
+ if (aco_dealloc_fn != NULL) aco_dealloc_fn(co->saved_stack.ptr);
co->saved_stack.ptr = NULL;
- if (aco_dealloc_fn != NULL)
- aco_dealloc_fn(co);
+ if (aco_dealloc_fn != NULL) aco_dealloc_fn(co);
}
}
-public void aco_exit_fn(void*_) {
- aco_exit();
-}
+public
+void aco_exit_fn(void *_) { aco_exit(); }
diff --git a/examples/coroutines/aco.h b/examples/coroutines/aco.h
index 80d5542b..6bdfb4dc 100644
--- a/examples/coroutines/aco.h
+++ b/examples/coroutines/aco.h
@@ -26,7 +26,7 @@
#include <unistd.h>
#ifdef ACO_USE_VALGRIND
- #include <valgrind/valgrind.h>
+#include <valgrind/valgrind.h>
#endif
#ifdef __cplusplus
@@ -38,30 +38,30 @@ extern "C" {
#define ACO_VERSION_PATCH 0
#ifdef __i386__
- #define ACO_REG_IDX_RETADDR 0
- #define ACO_REG_IDX_SP 1
- #define ACO_REG_IDX_BP 2
- #define ACO_REG_IDX_ARG1 0
- #define ACO_REG_IDX_FPU 6
+#define ACO_REG_IDX_RETADDR 0
+#define ACO_REG_IDX_SP 1
+#define ACO_REG_IDX_BP 2
+#define ACO_REG_IDX_ARG1 0
+#define ACO_REG_IDX_FPU 6
#elif __x86_64__
- #define ACO_REG_IDX_RETADDR 4
- #define ACO_REG_IDX_SP 5
- #define ACO_REG_IDX_BP 7
- #define ACO_REG_IDX_EDI 8
- #define ACO_REG_IDX_FPU 8
+#define ACO_REG_IDX_RETADDR 4
+#define ACO_REG_IDX_SP 5
+#define ACO_REG_IDX_BP 7
+#define ACO_REG_IDX_EDI 8
+#define ACO_REG_IDX_FPU 8
#else
- #error "platform not supported yet"
+#error "platform not supported yet"
#endif
typedef struct {
- void* ptr;
+ void *ptr;
size_t sz;
size_t valid_sz;
// max copy size in bytes
size_t max_cpsz;
// copy from shared stack to this saved stack
size_t ct_save;
- // copy from this saved stack to shared stack
+ // copy from this saved stack to shared stack
size_t ct_restore;
} aco_saved_stack_t;
@@ -69,16 +69,16 @@ struct aco_s;
typedef struct aco_s aco_t;
typedef struct {
- void* ptr;
+ void *ptr;
size_t sz;
- void* align_highptr;
- void* align_retptr;
+ void *align_highptr;
+ void *align_retptr;
size_t align_validsz;
size_t align_limit;
- aco_t* owner;
+ aco_t *owner;
bool guard_page_enabled;
- void* real_ptr;
+ void *real_ptr;
size_t real_sz;
#ifdef ACO_USE_VALGRIND
@@ -86,128 +86,126 @@ typedef struct {
#endif
} aco_shared_stack_t;
-typedef void (*aco_cofuncp_t)(void*);
+typedef void (*aco_cofuncp_t)(void *);
struct aco_s {
// cpu registers' state
#ifdef __i386__
- #ifdef ACO_CONFIG_SHARE_FPU_MXCSR_ENV
- void* reg[6];
- #else
- void* reg[8];
- #endif
+#ifdef ACO_CONFIG_SHARE_FPU_MXCSR_ENV
+ void *reg[6];
+#else
+ void *reg[8];
+#endif
#elif __x86_64__
- #ifdef ACO_CONFIG_SHARE_FPU_MXCSR_ENV
- void* reg[8];
- #else
- void* reg[9];
- #endif
+#ifdef ACO_CONFIG_SHARE_FPU_MXCSR_ENV
+ void *reg[8];
+#else
+ void *reg[9];
+#endif
#else
- #error "platform not supported yet"
+#error "platform not supported yet"
#endif
- aco_t* main_co;
- void* arg;
- bool is_finished;
+ aco_t *main_co;
+ void *arg;
+ bool is_finished;
aco_cofuncp_t fp;
-
- aco_saved_stack_t saved_stack;
- aco_shared_stack_t* shared_stack;
+
+ aco_saved_stack_t saved_stack;
+ aco_shared_stack_t *shared_stack;
};
#define aco_likely(x) (__builtin_expect(!!(x), 1))
#define aco_unlikely(x) (__builtin_expect(!!(x), 0))
-#define aco_assert(EX) ((aco_likely(EX))?((void)0):(abort()))
+#define aco_assert(EX) ((aco_likely(EX)) ? ((void)0) : (abort()))
-#define aco_assertptr(ptr) ((aco_likely((ptr) != NULL))?((void)0):(abort()))
+#define aco_assertptr(ptr) ((aco_likely((ptr) != NULL)) ? ((void)0) : (abort()))
#if defined(aco_attr_no_asan)
- #error "aco_attr_no_asan already defined"
+#error "aco_attr_no_asan already defined"
#endif
#if defined(ACO_USE_ASAN)
- #if defined(__has_feature)
- #if __has_feature(__address_sanitizer__)
- #define aco_attr_no_asan \
- __attribute__((__no_sanitize_address__))
- #endif
- #endif
- #if defined(__SANITIZE_ADDRESS__) && !defined(aco_attr_no_asan)
- #define aco_attr_no_asan \
- __attribute__((__no_sanitize_address__))
- #endif
+#if defined(__has_feature)
+#if __has_feature(__address_sanitizer__)
+#define aco_attr_no_asan __attribute__((__no_sanitize_address__))
+#endif
+#endif
+#if defined(__SANITIZE_ADDRESS__) && !defined(aco_attr_no_asan)
+#define aco_attr_no_asan __attribute__((__no_sanitize_address__))
+#endif
#endif
#ifndef aco_attr_no_asan
- #define aco_attr_no_asan
+#define aco_attr_no_asan
#endif
void aco_runtime_test(void);
-void aco_set_allocator(void* (*alloc)(size_t), void (*dealloc)(void*));
+void aco_set_allocator(void *(*alloc)(size_t), void (*dealloc)(void *));
void aco_thread_init(aco_cofuncp_t last_word_co_fp);
-void aco_yield_asm(aco_t* from_co, aco_t* to_co) __asm__("aco_yield_asm"); // asm
+void aco_yield_asm(aco_t *from_co, aco_t *to_co) __asm__("aco_yield_asm"); // asm
-void aco_save_fpucw_mxcsr(void* p) __asm__("aco_save_fpucw_mxcsr"); // asm
+void aco_save_fpucw_mxcsr(void *p) __asm__("aco_save_fpucw_mxcsr"); // asm
void aco_funcp_protector_asm(void) __asm__("aco_funcp_protector_asm"); // asm
void aco_funcp_protector(void);
-aco_shared_stack_t* aco_shared_stack_new(size_t sz);
+aco_shared_stack_t *aco_shared_stack_new(size_t sz);
-aco_shared_stack_t* aco_shared_stack_new2(size_t sz, bool guard_page_enabled);
+aco_shared_stack_t *aco_shared_stack_new2(size_t sz, bool guard_page_enabled);
-void aco_shared_stack_destroy(aco_shared_stack_t* sstk);
+void aco_shared_stack_destroy(aco_shared_stack_t *sstk);
-aco_t* aco_create(
- aco_t* main_co,
- aco_shared_stack_t* shared_stack,
- size_t saved_stack_sz,
- aco_cofuncp_t fp, void* arg
-);
+aco_t *aco_create(aco_t *main_co, aco_shared_stack_t *shared_stack, size_t saved_stack_sz, aco_cofuncp_t fp, void *arg);
// aco's Global Thread Local Storage variable `co`
#ifdef __TINYC__
- #error "TinyCC doesn't support thread-local storage!"
+#error "TinyCC doesn't support thread-local storage!"
#else
-extern __thread aco_t* aco_gtls_co;
+extern __thread aco_t *aco_gtls_co;
#endif
-aco_attr_no_asan
-void aco_resume(aco_t* resume_co);
+aco_attr_no_asan void aco_resume(aco_t *resume_co);
-//void aco_yield1(aco_t* yield_co);
-#define aco_yield1(yield_co) do { \
- aco_assertptr((yield_co)); \
- aco_assertptr((yield_co)->main_co); \
- aco_yield_asm((yield_co), (yield_co)->main_co); \
-} while (0)
+// void aco_yield1(aco_t* yield_co);
+#define aco_yield1(yield_co) \
+ do { \
+ aco_assertptr((yield_co)); \
+ aco_assertptr((yield_co)->main_co); \
+ aco_yield_asm((yield_co), (yield_co)->main_co); \
+ } while (0)
#define aco_yield() aco_yield1(aco_gtls_co)
#define aco_get_arg() (aco_gtls_co->arg)
-#define aco_get_co() ({(void)0; aco_gtls_co;})
+#define aco_get_co() \
+ ({ \
+ (void)0; \
+ aco_gtls_co; \
+ })
-void aco_destroy(aco_t* co);
+void aco_destroy(aco_t *co);
-#define aco_is_main_co(co) ({((co)->main_co) == NULL;})
+#define aco_is_main_co(co) ({ ((co)->main_co) == NULL; })
-#define aco_exit1(co) do { \
- (co)->is_finished = true; \
- aco_assert((co)->shared_stack->owner == (co)); \
- (co)->shared_stack->owner = NULL; \
- (co)->shared_stack->align_validsz = 0; \
- aco_yield1((co)); \
- aco_assert(0); \
-} while (0)
+#define aco_exit1(co) \
+ do { \
+ (co)->is_finished = true; \
+ aco_assert((co)->shared_stack->owner == (co)); \
+ (co)->shared_stack->owner = NULL; \
+ (co)->shared_stack->align_validsz = 0; \
+ aco_yield1((co)); \
+ aco_assert(0); \
+ } while (0)
#define aco_exit() aco_exit1(aco_gtls_co)
-void aco_exit_fn(void*);
+void aco_exit_fn(void *);
#ifdef __cplusplus
}
diff --git a/lib/commands/commands.c b/lib/commands/commands.c
index 80710387..4a6272b9 100644
--- a/lib/commands/commands.c
+++ b/lib/commands/commands.c
@@ -18,16 +18,14 @@
#define WRITE_END 1
static void xpipe(int fd[2]) {
- if (pipe(fd) != 0)
- fail("Failed to create pipe: ", strerror(errno));
+ if (pipe(fd) != 0) fail("Failed to create pipe: ", strerror(errno));
}
-int run_command(Text_t exe, List_t arg_list, Table_t env_table,
- OptionalList_t input_bytes, List_t *output_bytes, List_t *error_bytes)
-{
+int run_command(Text_t exe, List_t arg_list, Table_t env_table, OptionalList_t input_bytes, List_t *output_bytes,
+ List_t *error_bytes) {
pthread_testcancel();
- struct sigaction sa = { .sa_handler = SIG_IGN }, oldint, oldquit;
+ struct sigaction sa = {.sa_handler = SIG_IGN}, oldint, oldquit;
sigaction(SIGINT, &sa, &oldint);
sigaction(SIGQUIT, &sa, &oldquit);
sigaddset(&sa.sa_mask, SIGCHLD);
@@ -40,7 +38,7 @@ int run_command(Text_t exe, List_t arg_list, Table_t env_table,
posix_spawnattr_init(&attr);
posix_spawnattr_setsigmask(&attr, &old);
posix_spawnattr_setsigdefault(&attr, &reset);
- posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGDEF|POSIX_SPAWN_SETSIGMASK);
+ posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK);
int child_inpipe[2], child_outpipe[2], child_errpipe[2];
if (input_bytes.length >= 0) xpipe(child_inpipe);
@@ -65,10 +63,11 @@ int run_command(Text_t exe, List_t arg_list, Table_t env_table,
const char *exe_str = Text$as_c_string(exe);
List_t arg_strs = {};
- List$insert_value(&arg_strs, exe_str, I(0), sizeof(char*));
+ List$insert_value(&arg_strs, exe_str, I(0), sizeof(char *));
for (int64_t i = 0; i < arg_list.length; i++)
- List$insert_value(&arg_strs, Text$as_c_string(*(Text_t*)(arg_list.data + i*arg_list.stride)), I(0), sizeof(char*));
- List$insert_value(&arg_strs, NULL, I(0), sizeof(char*));
+ List$insert_value(&arg_strs, Text$as_c_string(*(Text_t *)(arg_list.data + i * arg_list.stride)), I(0),
+ sizeof(char *));
+ List$insert_value(&arg_strs, NULL, I(0), sizeof(char *));
char **args = arg_strs.data;
extern char **environ;
@@ -76,24 +75,24 @@ int run_command(Text_t exe, List_t arg_list, Table_t env_table,
if (env_table.entries.length > 0) {
List_t env_list = {}; // List of const char*
for (char **e = environ; *e; e++)
- List$insert(&env_list, e, I(0), sizeof(char*));
+ List$insert(&env_list, e, I(0), sizeof(char *));
for (int64_t i = 0; i < env_table.entries.length; i++) {
- struct { Text_t key, value; } *entry = env_table.entries.data + env_table.entries.stride*i;
+ struct {
+ Text_t key, value;
+ } *entry = env_table.entries.data + env_table.entries.stride * i;
const char *env_entry = String(entry->key, "=", entry->value);
- List$insert(&env_list, &env_entry, I(0), sizeof(char*));
+ List$insert(&env_list, &env_entry, I(0), sizeof(char *));
}
- List$insert_value(&env_list, NULL, I(0), sizeof(char*));
- assert(env_list.stride == sizeof(char*));
+ List$insert_value(&env_list, NULL, I(0), sizeof(char *));
+ assert(env_list.stride == sizeof(char *));
env = env_list.data;
}
pid_t pid;
- int ret = exe_str[0] == '/' ?
- posix_spawn(&pid, exe_str, &actions, &attr, args, env)
- : posix_spawnp(&pid, exe_str, &actions, &attr, args, env);
- if (ret != 0)
- return -1;
+ int ret = exe_str[0] == '/' ? posix_spawn(&pid, exe_str, &actions, &attr, args, env)
+ : posix_spawnp(&pid, exe_str, &actions, &attr, args, env);
+ if (ret != 0) return -1;
posix_spawnattr_destroy(&attr);
posix_spawn_file_actions_destroy(&actions);
@@ -103,19 +102,16 @@ int run_command(Text_t exe, List_t arg_list, Table_t env_table,
if (error_bytes) close(child_errpipe[WRITE_END]);
struct pollfd pollfds[3] = {};
- if (input_bytes.length >= 0) pollfds[0] = (struct pollfd){.fd=child_inpipe[WRITE_END], .events=POLLOUT};
- if (output_bytes) pollfds[1] = (struct pollfd){.fd=child_outpipe[WRITE_END], .events=POLLIN};
- if (error_bytes) pollfds[2] = (struct pollfd){.fd=child_errpipe[WRITE_END], .events=POLLIN};
+ if (input_bytes.length >= 0) pollfds[0] = (struct pollfd){.fd = child_inpipe[WRITE_END], .events = POLLOUT};
+ if (output_bytes) pollfds[1] = (struct pollfd){.fd = child_outpipe[WRITE_END], .events = POLLIN};
+ if (error_bytes) pollfds[2] = (struct pollfd){.fd = child_errpipe[WRITE_END], .events = POLLIN};
- if (input_bytes.length > 0 && input_bytes.stride != 1)
- List$compact(&input_bytes, sizeof(char));
- if (output_bytes)
- *output_bytes = (List_t){.atomic=1, .stride=1, .length=0};
- if (error_bytes)
- *error_bytes = (List_t){.atomic=1, .stride=1, .length=0};
+ if (input_bytes.length > 0 && input_bytes.stride != 1) List$compact(&input_bytes, sizeof(char));
+ if (output_bytes) *output_bytes = (List_t){.atomic = 1, .stride = 1, .length = 0};
+ if (error_bytes) *error_bytes = (List_t){.atomic = 1, .stride = 1, .length = 0};
while (input_bytes.length > 0 || output_bytes || error_bytes) {
- (void)poll(pollfds, sizeof(pollfds)/sizeof(pollfds[0]), -1); // Wait for data or readiness
+ (void)poll(pollfds, sizeof(pollfds) / sizeof(pollfds[0]), -1); // Wait for data or readiness
bool did_something = false;
if (input_bytes.length >= 0 && pollfds[0].revents) {
if (input_bytes.length > 0) {
@@ -171,10 +167,8 @@ int run_command(Text_t exe, List_t arg_list, Table_t env_table,
int status = 0;
if (ret == 0) {
while (waitpid(pid, &status, 0) < 0 && errno == EINTR) {
- if (WIFEXITED(status) || WIFSIGNALED(status))
- break;
- else if (WIFSTOPPED(status))
- kill(pid, SIGCONT);
+ if (WIFEXITED(status) || WIFSIGNALED(status)) break;
+ else if (WIFSTOPPED(status)) kill(pid, SIGCONT);
}
}
@@ -195,8 +189,7 @@ typedef struct {
FILE *out;
} child_info_t;
-static void _line_reader_cleanup(child_info_t *child)
-{
+static void _line_reader_cleanup(child_info_t *child) {
if (child && child->out) {
fclose(child->out);
child->out = NULL;
@@ -207,8 +200,7 @@ static void _line_reader_cleanup(child_info_t *child)
}
}
-static Text_t _next_line(child_info_t *child)
-{
+static Text_t _next_line(child_info_t *child) {
if (!child || !child->out) return NONE_TEXT;
char *line = NULL;
@@ -219,19 +211,17 @@ static Text_t _next_line(child_info_t *child)
return NONE_TEXT;
}
- while (len > 0 && (line[len-1] == '\r' || line[len-1] == '\n'))
+ while (len > 0 && (line[len - 1] == '\r' || line[len - 1] == '\n'))
--len;
- if (u8_check((uint8_t*)line, (size_t)len) != NULL)
- fail("Invalid UTF8!");
+ if (u8_check((uint8_t *)line, (size_t)len) != NULL) fail("Invalid UTF8!");
Text_t line_text = Text$from_strn(line, len);
free(line);
return line_text;
}
-OptionalClosure_t command_by_line(Text_t exe, List_t arg_list, Table_t env_table)
-{
+OptionalClosure_t command_by_line(Text_t exe, List_t arg_list, Table_t env_table) {
posix_spawnattr_t attr;
posix_spawnattr_init(&attr);
@@ -246,10 +236,11 @@ OptionalClosure_t command_by_line(Text_t exe, List_t arg_list, Table_t env_table
const char *exe_str = Text$as_c_string(exe);
List_t arg_strs = {};
- List$insert_value(&arg_strs, exe_str, I(0), sizeof(char*));
+ List$insert_value(&arg_strs, exe_str, I(0), sizeof(char *));
for (int64_t i = 0; i < arg_list.length; i++)
- List$insert_value(&arg_strs, Text$as_c_string(*(Text_t*)(arg_list.data + i*arg_list.stride)), I(0), sizeof(char*));
- List$insert_value(&arg_strs, NULL, I(0), sizeof(char*));
+ List$insert_value(&arg_strs, Text$as_c_string(*(Text_t *)(arg_list.data + i * arg_list.stride)), I(0),
+ sizeof(char *));
+ List$insert_value(&arg_strs, NULL, I(0), sizeof(char *));
char **args = arg_strs.data;
extern char **environ;
@@ -257,24 +248,24 @@ OptionalClosure_t command_by_line(Text_t exe, List_t arg_list, Table_t env_table
if (env_table.entries.length > 0) {
List_t env_list = {}; // List of const char*
for (char **e = environ; *e; e++)
- List$insert(&env_list, e, I(0), sizeof(char*));
+ List$insert(&env_list, e, I(0), sizeof(char *));
for (int64_t i = 0; i < env_table.entries.length; i++) {
- struct { Text_t key, value; } *entry = env_table.entries.data + env_table.entries.stride*i;
+ struct {
+ Text_t key, value;
+ } *entry = env_table.entries.data + env_table.entries.stride * i;
const char *env_entry = String(entry->key, "=", entry->value);
- List$insert(&env_list, &env_entry, I(0), sizeof(char*));
+ List$insert(&env_list, &env_entry, I(0), sizeof(char *));
}
- List$insert_value(&env_list, NULL, I(0), sizeof(char*));
- assert(env_list.stride == sizeof(char*));
+ List$insert_value(&env_list, NULL, I(0), sizeof(char *));
+ assert(env_list.stride == sizeof(char *));
env = env_list.data;
}
pid_t pid;
- int ret = exe_str[0] == '/' ?
- posix_spawn(&pid, exe_str, &actions, &attr, args, env)
- : posix_spawnp(&pid, exe_str, &actions, &attr, args, env);
- if (ret != 0)
- return NONE_CLOSURE;
+ int ret = exe_str[0] == '/' ? posix_spawn(&pid, exe_str, &actions, &attr, args, env)
+ : posix_spawnp(&pid, exe_str, &actions, &attr, args, env);
+ if (ret != 0) return NONE_CLOSURE;
posix_spawnattr_destroy(&attr);
posix_spawn_file_actions_destroy(&actions);
@@ -284,8 +275,8 @@ OptionalClosure_t command_by_line(Text_t exe, List_t arg_list, Table_t env_table
child_info_t *child_info = GC_MALLOC(sizeof(child_info_t));
child_info->out = fdopen(child_outpipe[READ_END], "r");
child_info->pid = pid;
- GC_register_finalizer(child_info, (void*)_line_reader_cleanup, NULL, NULL, NULL);
- return (Closure_t){.fn=(void*)_next_line, .userdata=child_info};
+ GC_register_finalizer(child_info, (void *)_line_reader_cleanup, NULL, NULL, NULL);
+ return (Closure_t){.fn = (void *)_next_line, .userdata = child_info};
}
#undef READ_END
diff --git a/lib/patterns/match_type.h b/lib/patterns/match_type.h
index abbc4fce..911d66fc 100644
--- a/lib/patterns/match_type.h
+++ b/lib/patterns/match_type.h
@@ -5,4 +5,3 @@ typedef struct {
Int_t index;
List_t captures;
} XMatch;
-
diff --git a/lib/patterns/patterns.c b/lib/patterns/patterns.c
index 224a00a0..0bdbbf58 100644
--- a/lib/patterns/patterns.c
+++ b/lib/patterns/patterns.c
@@ -20,10 +20,10 @@ typedef struct {
Text_t text;
Int_t index;
List_t captures;
- bool is_none:1;
+ bool is_none : 1;
} OptionalPatternMatch;
-#define NONE_MATCH ((OptionalPatternMatch){.is_none=true})
+#define NONE_MATCH ((OptionalPatternMatch){.is_none = true})
typedef struct {
int64_t index, length;
@@ -45,18 +45,15 @@ typedef struct {
static Text_t replace_list(Text_t text, List_t replacements, Text_t backref_pat, bool recursive);
-static INLINE void skip_whitespace(TextIter_t *state, int64_t *i)
-{
+static INLINE void skip_whitespace(TextIter_t *state, int64_t *i) {
while (*i < state->stack[0].text.length) {
int32_t grapheme = Text$get_grapheme_fast(state, *i);
- if (grapheme > 0 && !uc_is_property_white_space((ucs4_t)grapheme))
- return;
+ if (grapheme > 0 && !uc_is_property_white_space((ucs4_t)grapheme)) return;
*i += 1;
}
}
-static INLINE bool match_grapheme(TextIter_t *state, int64_t *i, int32_t grapheme)
-{
+static INLINE bool match_grapheme(TextIter_t *state, int64_t *i, int32_t grapheme) {
if (*i < state->stack[0].text.length && Text$get_grapheme_fast(state, *i) == grapheme) {
*i += 1;
return true;
@@ -64,8 +61,7 @@ static INLINE bool match_grapheme(TextIter_t *state, int64_t *i, int32_t graphem
return false;
}
-static INLINE bool match_str(TextIter_t *state, int64_t *i, const char *str)
-{
+static INLINE bool match_str(TextIter_t *state, int64_t *i, const char *str) {
int64_t matched = 0;
while (matched[str]) {
if (*i + matched >= state->stack[0].text.length || Text$get_grapheme_fast(state, *i + matched) != str[matched])
@@ -76,21 +72,19 @@ static INLINE bool match_str(TextIter_t *state, int64_t *i, const char *str)
return true;
}
-static int64_t parse_int(TextIter_t *state, int64_t *i)
-{
+static int64_t parse_int(TextIter_t *state, int64_t *i) {
int64_t value = 0;
for (;; *i += 1) {
uint32_t grapheme = Text$get_main_grapheme_fast(state, *i);
int digit = uc_digit_value(grapheme);
if (digit < 0) break;
- if (value >= INT64_MAX/10) break;
- value = 10*value + digit;
+ if (value >= INT64_MAX / 10) break;
+ value = 10 * value + digit;
}
return value;
}
-static const char *get_property_name(TextIter_t *state, int64_t *i)
-{
+static const char *get_property_name(TextIter_t *state, int64_t *i) {
skip_whitespace(state, i);
char *name = GC_MALLOC_ATOMIC(UNINAME_MAX);
char *dest = name;
@@ -99,8 +93,7 @@ static const char *get_property_name(TextIter_t *state, int64_t *i)
if (!(grapheme & ~0xFF) && (isalnum(grapheme) || grapheme == ' ' || grapheme == '_' || grapheme == '-')) {
*dest = (char)grapheme;
++dest;
- if (dest >= name + UNINAME_MAX - 1)
- break;
+ if (dest >= name + UNINAME_MAX - 1) break;
} else {
break;
}
@@ -115,28 +108,36 @@ static const char *get_property_name(TextIter_t *state, int64_t *i)
return name;
}
-#define EAT1(state, index, cond) ({\
- int32_t grapheme = Text$get_grapheme_fast(state, index); \
- bool success = (cond); \
- if (success) index += 1; \
- success; })
-
-#define EAT2(state, index, cond1, cond2) ({\
- int32_t grapheme = Text$get_grapheme_fast(state, index); \
- bool success = (cond1); \
- if (success) { \
- grapheme = Text$get_grapheme_fast(state, index + 1); \
- success = (cond2); \
- if (success) \
- index += 2; \
- } \
- success; })
-
-
-#define EAT_MANY(state, index, cond) ({ int64_t _n = 0; while (EAT1(state, index, cond)) { _n += 1; } _n; })
-
-static int64_t match_email(TextIter_t *state, int64_t index)
-{
+#define EAT1(state, index, cond) \
+ ({ \
+ int32_t grapheme = Text$get_grapheme_fast(state, index); \
+ bool success = (cond); \
+ if (success) index += 1; \
+ success; \
+ })
+
+#define EAT2(state, index, cond1, cond2) \
+ ({ \
+ int32_t grapheme = Text$get_grapheme_fast(state, index); \
+ bool success = (cond1); \
+ if (success) { \
+ grapheme = Text$get_grapheme_fast(state, index + 1); \
+ success = (cond2); \
+ if (success) index += 2; \
+ } \
+ success; \
+ })
+
+#define EAT_MANY(state, index, cond) \
+ ({ \
+ int64_t _n = 0; \
+ while (EAT1(state, index, cond)) { \
+ _n += 1; \
+ } \
+ _n; \
+ })
+
+static int64_t match_email(TextIter_t *state, int64_t index) {
// email = local "@" domain
// local = 1-64 ([a-zA-Z0-9!#$%&‘*+–/=?^_`.{|}~] | non-ascii)
// domain = dns-label ("." dns-label)*
@@ -144,8 +145,7 @@ static int64_t match_email(TextIter_t *state, int64_t index)
if (index > 0) {
uint32_t prev_codepoint = Text$get_main_grapheme_fast(state, index - 1);
- if (uc_is_property_alphabetic(prev_codepoint))
- return -1;
+ if (uc_is_property_alphabetic(prev_codepoint)) return -1;
}
int64_t start_index = index;
@@ -153,78 +153,65 @@ static int64_t match_email(TextIter_t *state, int64_t index)
// Local part:
int64_t local_len = 0;
static const char *allowed_local = "!#$%&‘*+–/=?^_`.{|}~";
- while (EAT1(state, index,
- (grapheme & ~0x7F) || isalnum((char)grapheme) || strchr(allowed_local, (char)grapheme))) {
+ while (EAT1(state, index, (grapheme & ~0x7F) || isalnum((char)grapheme) || strchr(allowed_local, (char)grapheme))) {
local_len += 1;
if (local_len > 64) return -1;
}
-
- if (!EAT1(state, index, grapheme == '@'))
- return -1;
+
+ if (!EAT1(state, index, grapheme == '@')) return -1;
// Host
int64_t host_len = 0;
do {
int64_t label_len = 0;
- while (EAT1(state, index,
- (grapheme & ~0x7F) || isalnum((char)grapheme) || grapheme == '-')) {
+ while (EAT1(state, index, (grapheme & ~0x7F) || isalnum((char)grapheme) || grapheme == '-')) {
label_len += 1;
if (label_len > 63) return -1;
}
- if (label_len == 0)
- return -1;
+ if (label_len == 0) return -1;
host_len += label_len;
- if (host_len > 255)
- return -1;
+ if (host_len > 255) return -1;
host_len += 1;
} while (EAT1(state, index, grapheme == '.'));
return index - start_index;
}
-static int64_t match_ipv6(TextIter_t *state, int64_t index)
-{
+static int64_t match_ipv6(TextIter_t *state, int64_t index) {
if (index > 0) {
int32_t prev_codepoint = Text$get_grapheme_fast(state, index - 1);
- if ((prev_codepoint & ~0x7F) && (isxdigit(prev_codepoint) || prev_codepoint == ':'))
- return -1;
+ if ((prev_codepoint & ~0x7F) && (isxdigit(prev_codepoint) || prev_codepoint == ':')) return -1;
}
int64_t start_index = index;
const int NUM_CLUSTERS = 8;
bool double_colon_used = false;
for (int cluster = 0; cluster < NUM_CLUSTERS; cluster++) {
for (int digits = 0; digits < 4; digits++) {
- if (!EAT1(state, index, ~(grapheme & ~0x7F) && isxdigit((char)grapheme)))
- break;
+ if (!EAT1(state, index, ~(grapheme & ~0x7F) && isxdigit((char)grapheme))) break;
}
- if (EAT1(state, index, ~(grapheme & ~0x7F) && isxdigit((char)grapheme)))
- return -1; // Too many digits
+ if (EAT1(state, index, ~(grapheme & ~0x7F) && isxdigit((char)grapheme))) return -1; // Too many digits
- if (cluster == NUM_CLUSTERS-1) {
+ if (cluster == NUM_CLUSTERS - 1) {
break;
} else if (!EAT1(state, index, grapheme == ':')) {
- if (double_colon_used)
- break;
+ if (double_colon_used) break;
return -1;
}
if (EAT1(state, index, grapheme == ':')) {
- if (double_colon_used)
- return -1;
+ if (double_colon_used) return -1;
double_colon_used = true;
}
}
return index - start_index;
}
-static int64_t match_ipv4(TextIter_t *state, int64_t index)
-{
+static int64_t match_ipv4(TextIter_t *state, int64_t index) {
if (index > 0) {
int32_t prev_codepoint = Text$get_grapheme_fast(state, index - 1);
- if ((prev_codepoint & ~0x7F) && (isdigit(prev_codepoint) || prev_codepoint == '.'))
- return -1;
+ if ((prev_codepoint & ~0x7F) && (isdigit(prev_codepoint) || prev_codepoint == '.')) return -1;
}
int64_t start_index = index;
@@ -237,27 +224,22 @@ static int64_t match_ipv4(TextIter_t *state, int64_t index)
}
}
- if (EAT1(state, index, ~(grapheme & ~0x7F) && isdigit((char)grapheme)))
- return -1; // Too many digits
+ if (EAT1(state, index, ~(grapheme & ~0x7F) && isdigit((char)grapheme))) return -1; // Too many digits
- if (cluster == NUM_CLUSTERS-1)
- break;
- else if (!EAT1(state, index, grapheme == '.'))
- return -1;
+ if (cluster == NUM_CLUSTERS - 1) break;
+ else if (!EAT1(state, index, grapheme == '.')) return -1;
}
return (index - start_index);
}
-static int64_t match_ip(TextIter_t *state, int64_t index)
-{
+static int64_t match_ip(TextIter_t *state, int64_t index) {
int64_t len = match_ipv6(state, index);
if (len >= 0) return len;
len = match_ipv4(state, index);
return (len >= 0) ? len : -1;
}
-static int64_t match_host(TextIter_t *state, int64_t index)
-{
+static int64_t match_host(TextIter_t *state, int64_t index) {
int64_t ip_len = match_ip(state, index);
if (ip_len > 0) return ip_len;
@@ -266,28 +248,24 @@ static int64_t match_host(TextIter_t *state, int64_t index)
ip_len = match_ip(state, index);
if (ip_len <= 0) return -1;
index += ip_len;
- if (match_grapheme(state, &index, ']'))
- return (index - start_index);
+ if (match_grapheme(state, &index, ']')) return (index - start_index);
return -1;
}
- if (!EAT1(state, index, isalpha(grapheme)))
- return -1;
+ if (!EAT1(state, index, isalpha(grapheme))) return -1;
static const char *non_host_chars = "/#?:@ \t\r\n<>[]{}\\^|\"`";
EAT_MANY(state, index, (grapheme & ~0x7F) || !strchr(non_host_chars, (char)grapheme));
return (index - start_index);
}
-static int64_t match_authority(TextIter_t *state, int64_t index)
-{
+static int64_t match_authority(TextIter_t *state, int64_t index) {
int64_t authority_start = index;
static const char *non_segment_chars = "/#?:@ \t\r\n<>[]{}\\^|\"`.";
// Optional user@ prefix:
int64_t username_len = EAT_MANY(state, index, (grapheme & ~0x7F) || !strchr(non_segment_chars, (char)grapheme));
- if (username_len < 1 || !EAT1(state, index, grapheme == '@'))
- index = authority_start; // No user@ part
+ if (username_len < 1 || !EAT1(state, index, grapheme == '@')) index = authority_start; // No user@ part
// Host:
int64_t host_len = match_host(state, index);
@@ -296,14 +274,12 @@ static int64_t match_authority(TextIter_t *state, int64_t index)
// Port:
if (EAT1(state, index, grapheme == ':')) {
- if (EAT_MANY(state, index, !(grapheme & ~0x7F) && isdigit(grapheme)) == 0)
- return -1;
+ if (EAT_MANY(state, index, !(grapheme & ~0x7F) && isdigit(grapheme)) == 0) return -1;
}
return (index - authority_start);
}
-static int64_t match_uri(TextIter_t *state, int64_t index)
-{
+static int64_t match_uri(TextIter_t *state, int64_t index) {
// URI = scheme ":" ["//" authority] path ["?" query] ["#" fragment]
// scheme = [a-zA-Z] [a-zA-Z0-9+.-]
// authority = [userinfo "@"] host [":" port]
@@ -311,25 +287,22 @@ static int64_t match_uri(TextIter_t *state, int64_t index)
if (index > 0) {
// Don't match if we're not at a word edge:
uint32_t prev_codepoint = Text$get_main_grapheme_fast(state, index - 1);
- if (uc_is_property_alphabetic(prev_codepoint))
- return -1;
+ if (uc_is_property_alphabetic(prev_codepoint)) return -1;
}
int64_t start_index = index;
// Scheme:
- if (!EAT1(state, index, isalpha(grapheme)))
- return -1;
- EAT_MANY(state, index, !(grapheme & ~0x7F) && (isalnum(grapheme) || grapheme == '+' || grapheme == '.' || grapheme == '-'));
- if (!match_grapheme(state, &index, ':'))
- return -1;
+ if (!EAT1(state, index, isalpha(grapheme))) return -1;
+ EAT_MANY(state, index,
+ !(grapheme & ~0x7F) && (isalnum(grapheme) || grapheme == '+' || grapheme == '.' || grapheme == '-'));
+ if (!match_grapheme(state, &index, ':')) return -1;
// Authority:
int64_t authority_len;
if (match_str(state, &index, "//")) {
authority_len = match_authority(state, index);
- if (authority_len > 0)
- index += authority_len;
+ if (authority_len > 0) index += authority_len;
} else {
authority_len = 0;
}
@@ -344,92 +317,75 @@ static int64_t match_uri(TextIter_t *state, int64_t index)
static const char *non_query = " \"#<>[]{}\\^`|";
EAT_MANY(state, index, (grapheme & ~0x7F) || !strchr(non_query, (char)grapheme));
}
-
+
if (EAT1(state, index, grapheme == '#')) { // Fragment
static const char *non_fragment = " \"#<>[]{}\\^`|";
EAT_MANY(state, index, (grapheme & ~0x7F) || !strchr(non_fragment, (char)grapheme));
}
}
- if (authority_len <= 0 && index == path_start)
- return -1;
+ if (authority_len <= 0 && index == path_start) return -1;
return index - start_index;
}
-static int64_t match_url(TextIter_t *state, int64_t index)
-{
+static int64_t match_url(TextIter_t *state, int64_t index) {
int64_t lookahead = index;
- if (!(match_str(state, &lookahead, "https:")
- || match_str(state, &lookahead, "http:")
- || match_str(state, &lookahead, "ftp:")
- || match_str(state, &lookahead, "wss:")
- || match_str(state, &lookahead, "ws:")))
+ if (!(match_str(state, &lookahead, "https:") || match_str(state, &lookahead, "http:")
+ || match_str(state, &lookahead, "ftp:") || match_str(state, &lookahead, "wss:")
+ || match_str(state, &lookahead, "ws:")))
return -1;
return match_uri(state, index);
}
-static int64_t match_id(TextIter_t *state, int64_t index)
-{
- if (!EAT1(state, index, uc_is_property((ucs4_t)grapheme, UC_PROPERTY_XID_START)))
- return -1;
+static int64_t match_id(TextIter_t *state, int64_t index) {
+ if (!EAT1(state, index, uc_is_property((ucs4_t)grapheme, UC_PROPERTY_XID_START))) return -1;
return 1 + EAT_MANY(state, index, uc_is_property((ucs4_t)grapheme, UC_PROPERTY_XID_CONTINUE));
}
-static int64_t match_int(TextIter_t *state, int64_t index)
-{
+static int64_t match_int(TextIter_t *state, int64_t index) {
int64_t negative = EAT1(state, index, grapheme == '-') ? 1 : 0;
int64_t len = EAT_MANY(state, index, uc_is_property((ucs4_t)grapheme, UC_PROPERTY_DECIMAL_DIGIT));
return len > 0 ? negative + len : -1;
}
-static int64_t match_alphanumeric(TextIter_t *state, int64_t index)
-{
+static int64_t match_alphanumeric(TextIter_t *state, int64_t index) {
return EAT1(state, index, uc_is_property_alphabetic((ucs4_t)grapheme) || uc_is_property_numeric((ucs4_t)grapheme))
- ? 1 : -1;
+ ? 1
+ : -1;
}
-static int64_t match_num(TextIter_t *state, int64_t index)
-{
+static int64_t match_num(TextIter_t *state, int64_t index) {
bool negative = EAT1(state, index, grapheme == '-') ? 1 : 0;
- int64_t pre_decimal = EAT_MANY(state, index,
- uc_is_property((ucs4_t)grapheme, UC_PROPERTY_DECIMAL_DIGIT));
+ int64_t pre_decimal = EAT_MANY(state, index, uc_is_property((ucs4_t)grapheme, UC_PROPERTY_DECIMAL_DIGIT));
bool decimal = (EAT1(state, index, grapheme == '.') == 1);
- int64_t post_decimal = decimal ? EAT_MANY(state, index,
- uc_is_property((ucs4_t)grapheme, UC_PROPERTY_DECIMAL_DIGIT)) : 0;
- if (pre_decimal == 0 && post_decimal == 0)
- return -1;
+ int64_t post_decimal =
+ decimal ? EAT_MANY(state, index, uc_is_property((ucs4_t)grapheme, UC_PROPERTY_DECIMAL_DIGIT)) : 0;
+ if (pre_decimal == 0 && post_decimal == 0) return -1;
return negative + pre_decimal + decimal + post_decimal;
}
-static int64_t match_newline(TextIter_t *state, int64_t index)
-{
- if (index >= state->stack[0].text.length)
- return -1;
+static int64_t match_newline(TextIter_t *state, int64_t index) {
+ if (index >= state->stack[0].text.length) return -1;
uint32_t grapheme = index >= state->stack[0].text.length ? 0 : Text$get_main_grapheme_fast(state, index);
- if (grapheme == '\n')
- return 1;
- if (grapheme == '\r' && Text$get_grapheme_fast(state, index + 1) == '\n')
- return 2;
+ if (grapheme == '\n') return 1;
+ if (grapheme == '\r' && Text$get_grapheme_fast(state, index + 1) == '\n') return 2;
return -1;
}
-static int64_t match_pat(TextIter_t *state, int64_t index, pat_t pat)
-{
+static int64_t match_pat(TextIter_t *state, int64_t index, pat_t pat) {
Text_t text = state->stack[0].text;
int32_t grapheme = index >= text.length ? 0 : Text$get_grapheme_fast(state, index);
switch (pat.tag) {
case PAT_START: {
- if (index == 0)
- return pat.negated ? -1 : 0;
+ if (index == 0) return pat.negated ? -1 : 0;
return pat.negated ? 0 : -1;
}
case PAT_END: {
- if (index >= text.length)
- return pat.negated ? -1 : 0;
+ if (index >= text.length) return pat.negated ? -1 : 0;
return pat.negated ? 0 : -1;
}
case PAT_ANY: {
@@ -437,51 +393,40 @@ static int64_t match_pat(TextIter_t *state, int64_t index, pat_t pat)
return (index < text.length) ? 1 : -1;
}
case PAT_GRAPHEME: {
- if (index >= text.length)
- return -1;
- else if (grapheme == pat.grapheme)
- return pat.negated ? -1 : 1;
+ if (index >= text.length) return -1;
+ else if (grapheme == pat.grapheme) return pat.negated ? -1 : 1;
return pat.negated ? 1 : -1;
}
case PAT_PROPERTY: {
- if (index >= text.length)
- return -1;
- else if (uc_is_property((ucs4_t)grapheme, pat.property))
- return pat.negated ? -1 : 1;
+ if (index >= text.length) return -1;
+ else if (uc_is_property((ucs4_t)grapheme, pat.property)) return pat.negated ? -1 : 1;
return pat.negated ? 1 : -1;
}
case PAT_PAIR: {
// Nested punctuation: (?), [?], etc
- if (index >= text.length)
- return -1;
+ if (index >= text.length) return -1;
int32_t open = pat.pair_graphemes[0];
- if (grapheme != open)
- return pat.negated ? 1 : -1;
+ if (grapheme != open) return pat.negated ? 1 : -1;
int32_t close = pat.pair_graphemes[1];
int64_t depth = 1;
int64_t match_len = 1;
for (; depth > 0; match_len++) {
- if (index + match_len >= text.length)
- return pat.negated ? 1 : -1;
+ if (index + match_len >= text.length) return pat.negated ? 1 : -1;
int32_t c = Text$get_grapheme_fast(state, index + match_len);
- if (c == open)
- depth += 1;
- else if (c == close)
- depth -= 1;
+ if (c == open) depth += 1;
+ else if (c == close) depth -= 1;
}
return pat.negated ? -1 : match_len;
}
case PAT_QUOTE: {
// Nested quotes: "?", '?', etc
- if (index >= text.length)
- return -1;
+ if (index >= text.length) return -1;
int32_t open = pat.quote_graphemes[0];
- if (grapheme != open)
- return pat.negated ? 1 : -1;
+ if (grapheme != open) return pat.negated ? 1 : -1;
int32_t close = pat.quote_graphemes[1];
for (int64_t i = index + 1; i < text.length; i++) {
@@ -496,8 +441,7 @@ static int64_t match_pat(TextIter_t *state, int64_t index, pat_t pat)
}
case PAT_FUNCTION: {
int64_t match_len = pat.fn(state, index);
- if (match_len >= 0)
- return pat.negated ? -1 : match_len;
+ if (match_len >= 0) return pat.negated ? -1 : match_len;
return pat.negated ? 1 : -1;
}
default: errx(1, "Invalid pattern");
@@ -506,37 +450,32 @@ static int64_t match_pat(TextIter_t *state, int64_t index, pat_t pat)
return 0;
}
-static pat_t parse_next_pat(TextIter_t *state, int64_t *index)
-{
- if (EAT2(state, *index,
- uc_is_property((ucs4_t)grapheme, UC_PROPERTY_QUOTATION_MARK),
- grapheme == '?')) {
+static pat_t parse_next_pat(TextIter_t *state, int64_t *index) {
+ if (EAT2(state, *index, uc_is_property((ucs4_t)grapheme, UC_PROPERTY_QUOTATION_MARK), grapheme == '?')) {
// Quotations: "?", '?', etc
- int32_t open = Text$get_grapheme_fast(state, *index-2);
+ int32_t open = Text$get_grapheme_fast(state, *index - 2);
int32_t close = open;
- uc_mirror_char((ucs4_t)open, (ucs4_t*)&close);
- if (!match_grapheme(state, index, close))
- fail("Pattern's closing quote is missing: ", state->stack[0].text);
+ uc_mirror_char((ucs4_t)open, (ucs4_t *)&close);
+ if (!match_grapheme(state, index, close)) fail("Pattern's closing quote is missing: ", state->stack[0].text);
return (pat_t){
- .tag=PAT_QUOTE,
- .min=1, .max=1,
- .quote_graphemes={open, close},
+ .tag = PAT_QUOTE,
+ .min = 1,
+ .max = 1,
+ .quote_graphemes = {open, close},
};
- } else if (EAT2(state, *index,
- uc_is_property((ucs4_t)grapheme, UC_PROPERTY_PAIRED_PUNCTUATION),
- grapheme == '?')) {
+ } else if (EAT2(state, *index, uc_is_property((ucs4_t)grapheme, UC_PROPERTY_PAIRED_PUNCTUATION), grapheme == '?')) {
// Nested punctuation: (?), [?], etc
- int32_t open = Text$get_grapheme_fast(state, *index-2);
+ int32_t open = Text$get_grapheme_fast(state, *index - 2);
int32_t close = open;
- uc_mirror_char((ucs4_t)open, (ucs4_t*)&close);
- if (!match_grapheme(state, index, close))
- fail("Pattern's closing brace is missing: ", state->stack[0].text);
-
+ uc_mirror_char((ucs4_t)open, (ucs4_t *)&close);
+ if (!match_grapheme(state, index, close)) fail("Pattern's closing brace is missing: ", state->stack[0].text);
+
return (pat_t){
- .tag=PAT_PAIR,
- .min=1, .max=1,
- .pair_graphemes={open, close},
+ .tag = PAT_PAIR,
+ .min = 1,
+ .max = 1,
+ .pair_graphemes = {open, close},
};
} else if (EAT1(state, *index, grapheme == '{')) { // named patterns {id}, {2-3 hex}, etc.
skip_whitespace(state, index);
@@ -559,133 +498,127 @@ static pat_t parse_next_pat(TextIter_t *state, int64_t *index)
skip_whitespace(state, index);
bool negated = match_grapheme(state, index, '!');
-#define PAT(_tag, ...) ((pat_t){.min=min, .max=max, .negated=negated, .tag=_tag, __VA_ARGS__})
+#define PAT(_tag, ...) ((pat_t){.min = min, .max = max, .negated = negated, .tag = _tag, __VA_ARGS__})
const char *prop_name;
- if (match_str(state, index, ".."))
- prop_name = "..";
- else
- prop_name = get_property_name(state, index);
+ if (match_str(state, index, "..")) prop_name = "..";
+ else prop_name = get_property_name(state, index);
if (!prop_name) {
// Literal character, e.g. {1?}
skip_whitespace(state, index);
int32_t grapheme = Text$get_grapheme_fast(state, (*index)++);
- if (!match_grapheme(state, index, '}'))
- fail("Missing closing '}' in pattern: ", state->stack[0].text);
- return PAT(PAT_GRAPHEME, .grapheme=grapheme);
+ if (!match_grapheme(state, index, '}')) fail("Missing closing '}' in pattern: ", state->stack[0].text);
+ return PAT(PAT_GRAPHEME, .grapheme = grapheme);
} else if (strlen(prop_name) == 1) {
// Single letter names: {1+ A}
skip_whitespace(state, index);
- if (!match_grapheme(state, index, '}'))
- fail("Missing closing '}' in pattern: ", state->stack[0].text);
- return PAT(PAT_GRAPHEME, .grapheme=prop_name[0]);
+ if (!match_grapheme(state, index, '}')) fail("Missing closing '}' in pattern: ", state->stack[0].text);
+ return PAT(PAT_GRAPHEME, .grapheme = prop_name[0]);
}
skip_whitespace(state, index);
- if (!match_grapheme(state, index, '}'))
- fail("Missing closing '}' in pattern: ", state->stack[0].text);
+ if (!match_grapheme(state, index, '}')) fail("Missing closing '}' in pattern: ", state->stack[0].text);
switch (tolower(prop_name[0])) {
case '.':
if (prop_name[1] == '.') {
- if (negated)
- return ((pat_t){.tag=PAT_END, .min=min, .max=max, .non_capturing=true});
- else
- return PAT(PAT_ANY);
+ if (negated) return ((pat_t){.tag = PAT_END, .min = min, .max = max, .non_capturing = true});
+ else return PAT(PAT_ANY);
}
break;
case 'a':
if (strcasecmp(prop_name, "authority") == 0) {
- return PAT(PAT_FUNCTION, .fn=match_authority);
+ return PAT(PAT_FUNCTION, .fn = match_authority);
} else if (strcasecmp(prop_name, "alphanum") == 0 || strcasecmp(prop_name, "anum") == 0
|| strcasecmp(prop_name, "alphanumeric") == 0) {
- return PAT(PAT_FUNCTION, .fn=match_alphanumeric);
+ return PAT(PAT_FUNCTION, .fn = match_alphanumeric);
}
break;
- case 'c':
- if (strcasecmp(prop_name, "crlf") == 0)
- return PAT(PAT_FUNCTION, .fn=match_newline);
+ case 'c':
+ if (strcasecmp(prop_name, "crlf") == 0) return PAT(PAT_FUNCTION, .fn = match_newline);
break;
case 'd':
if (strcasecmp(prop_name, "digit") == 0) {
- return PAT(PAT_PROPERTY, .property=UC_PROPERTY_DECIMAL_DIGIT);
+ return PAT(PAT_PROPERTY, .property = UC_PROPERTY_DECIMAL_DIGIT);
}
break;
case 'e':
if (strcasecmp(prop_name, "end") == 0) {
- return PAT(PAT_END, .non_capturing=!negated);
+ return PAT(PAT_END, .non_capturing = !negated);
} else if (strcasecmp(prop_name, "email") == 0) {
- return PAT(PAT_FUNCTION, .fn=match_email);
+ return PAT(PAT_FUNCTION, .fn = match_email);
}
#if _LIBUNISTRING_VERSION >= 0x0100000
else if (strcasecmp(prop_name, "emoji") == 0) {
- return PAT(PAT_PROPERTY, .property=UC_PROPERTY_EMOJI);
+ return PAT(PAT_PROPERTY, .property = UC_PROPERTY_EMOJI);
}
#endif
break;
case 'h':
if (strcasecmp(prop_name, "host") == 0) {
- return PAT(PAT_FUNCTION, .fn=match_host);
+ return PAT(PAT_FUNCTION, .fn = match_host);
}
break;
case 'i':
if (strcasecmp(prop_name, "id") == 0) {
- return PAT(PAT_FUNCTION, .fn=match_id);
+ return PAT(PAT_FUNCTION, .fn = match_id);
} else if (strcasecmp(prop_name, "int") == 0) {
- return PAT(PAT_FUNCTION, .fn=match_int);
+ return PAT(PAT_FUNCTION, .fn = match_int);
} else if (strcasecmp(prop_name, "ipv4") == 0) {
- return PAT(PAT_FUNCTION, .fn=match_ipv4);
+ return PAT(PAT_FUNCTION, .fn = match_ipv4);
} else if (strcasecmp(prop_name, "ipv6") == 0) {
- return PAT(PAT_FUNCTION, .fn=match_ipv6);
+ return PAT(PAT_FUNCTION, .fn = match_ipv6);
} else if (strcasecmp(prop_name, "ip") == 0) {
- return PAT(PAT_FUNCTION, .fn=match_ip);
+ return PAT(PAT_FUNCTION, .fn = match_ip);
}
break;
case 'n':
if (strcasecmp(prop_name, "nl") == 0 || strcasecmp(prop_name, "newline") == 0) {
- return PAT(PAT_FUNCTION, .fn=match_newline);
+ return PAT(PAT_FUNCTION, .fn = match_newline);
} else if (strcasecmp(prop_name, "num") == 0) {
- return PAT(PAT_FUNCTION, .fn=match_num);
+ return PAT(PAT_FUNCTION, .fn = match_num);
}
break;
case 's':
if (strcasecmp(prop_name, "start") == 0) {
- return PAT(PAT_START, .non_capturing=!negated);
+ return PAT(PAT_START, .non_capturing = !negated);
}
break;
case 'u':
if (strcasecmp(prop_name, "uri") == 0) {
- return PAT(PAT_FUNCTION, .fn=match_uri);
+ return PAT(PAT_FUNCTION, .fn = match_uri);
} else if (strcasecmp(prop_name, "url") == 0) {
- return PAT(PAT_FUNCTION, .fn=match_url);
+ return PAT(PAT_FUNCTION, .fn = match_url);
}
break;
case 'w':
if (strcasecmp(prop_name, "word") == 0) {
- return PAT(PAT_FUNCTION, .fn=match_id);
+ return PAT(PAT_FUNCTION, .fn = match_id);
} else if (strcasecmp(prop_name, "ws") == 0 || strcasecmp(prop_name, "whitespace") == 0) {
- return PAT(PAT_PROPERTY, .property=UC_PROPERTY_WHITE_SPACE);
+ return PAT(PAT_PROPERTY, .property = UC_PROPERTY_WHITE_SPACE);
}
break;
default: break;
}
uc_property_t prop = uc_property_byname(prop_name);
- if (uc_property_is_valid(prop))
- return PAT(PAT_PROPERTY, .property=prop);
+ if (uc_property_is_valid(prop)) return PAT(PAT_PROPERTY, .property = prop);
ucs4_t grapheme = unicode_name_character(prop_name);
- if (grapheme == UNINAME_INVALID)
- fail("Not a valid property or character name: ", prop_name);
- return PAT(PAT_GRAPHEME, .grapheme=(int32_t)grapheme);
+ if (grapheme == UNINAME_INVALID) fail("Not a valid property or character name: ", prop_name);
+ return PAT(PAT_GRAPHEME, .grapheme = (int32_t)grapheme);
#undef PAT
} else {
- return (pat_t){.tag=PAT_GRAPHEME, .non_capturing=true, .min=1, .max=1, .grapheme=Text$get_grapheme_fast(state, (*index)++)};
+ return (pat_t){.tag = PAT_GRAPHEME,
+ .non_capturing = true,
+ .min = 1,
+ .max = 1,
+ .grapheme = Text$get_grapheme_fast(state, (*index)++)};
}
}
-static int64_t match(Text_t text, int64_t text_index, Text_t pattern, int64_t pattern_index, capture_t *captures, int64_t capture_index)
-{
+static int64_t match(Text_t text, int64_t text_index, Text_t pattern, int64_t pattern_index, capture_t *captures,
+ int64_t capture_index) {
if (pattern_index >= pattern.length) // End of the pattern
return 0;
@@ -713,7 +646,8 @@ static int64_t match(Text_t text, int64_t text_index, Text_t pattern, int64_t pa
}
if (pat.min == 0 && pattern_index < pattern.length) {
- next_match_len = match(text, text_index, pattern, pattern_index, captures, capture_index + (pat.non_capturing ? 0 : 1));
+ next_match_len =
+ match(text, text_index, pattern, pattern_index, captures, capture_index + (pat.non_capturing ? 0 : 1));
if (next_match_len >= 0) {
capture_len = 0;
goto success;
@@ -722,17 +656,16 @@ static int64_t match(Text_t text, int64_t text_index, Text_t pattern, int64_t pa
while (count < pat.max) {
int64_t match_len = match_pat(&text_state, text_index, pat);
- if (match_len < 0)
- break;
+ if (match_len < 0) break;
capture_len += match_len;
text_index += match_len;
count += 1;
if (pattern_index < pattern.length) { // More stuff after this
- if (count < pat.min)
- next_match_len = -1;
+ if (count < pat.min) next_match_len = -1;
else
- next_match_len = match(text, text_index, pattern, pattern_index, captures, capture_index + (pat.non_capturing ? 0 : 1));
+ next_match_len = match(text, text_index, pattern, pattern_index, captures,
+ capture_index + (pat.non_capturing ? 0 : 1));
} else {
next_match_len = 0;
}
@@ -748,32 +681,29 @@ static int64_t match(Text_t text, int64_t text_index, Text_t pattern, int64_t pa
}
}
- if (pattern_index < pattern.length && next_match_len >= 0)
- break; // Next guy exists and wants to stop here
+ if (pattern_index < pattern.length && next_match_len >= 0) break; // Next guy exists and wants to stop here
- if (text_index >= text.length)
- break;
+ if (text_index >= text.length) break;
}
- if (count < pat.min || next_match_len < 0)
- return -1;
+ if (count < pat.min || next_match_len < 0) return -1;
- success:
+success:
if (captures && capture_index < MAX_BACKREFS && !pat.non_capturing) {
if (pat.tag == PAT_PAIR || pat.tag == PAT_QUOTE) {
assert(capture_len > 0);
captures[capture_index] = (capture_t){
- .index=capture_start + 1, // Skip leading quote/paren
- .length=capture_len - 2, // Skip open/close
- .occupied=true,
- .recursive=(pat.tag == PAT_PAIR),
+ .index = capture_start + 1, // Skip leading quote/paren
+ .length = capture_len - 2, // Skip open/close
+ .occupied = true,
+ .recursive = (pat.tag == PAT_PAIR),
};
} else {
captures[capture_index] = (capture_t){
- .index=capture_start,
- .length=capture_len,
- .occupied=true,
- .recursive=false,
+ .index = capture_start,
+ .length = capture_len,
+ .occupied = true,
+ .recursive = false,
};
}
}
@@ -784,11 +714,10 @@ static int64_t match(Text_t text, int64_t text_index, Text_t pattern, int64_t pa
#undef EAT2
#undef EAT_MANY
-static int64_t _find(Text_t text, Text_t pattern, int64_t first, int64_t last, int64_t *match_length, capture_t *captures)
-{
+static int64_t _find(Text_t text, Text_t pattern, int64_t first, int64_t last, int64_t *match_length,
+ capture_t *captures) {
int32_t first_grapheme = Text$get_grapheme(pattern, 0);
- bool find_first = (first_grapheme != '{'
- && !uc_is_property((ucs4_t)first_grapheme, UC_PROPERTY_QUOTATION_MARK)
+ bool find_first = (first_grapheme != '{' && !uc_is_property((ucs4_t)first_grapheme, UC_PROPERTY_QUOTATION_MARK)
&& !uc_is_property((ucs4_t)first_grapheme, UC_PROPERTY_PAIRED_PUNCTUATION));
TextIter_t text_state = NEW_TEXT_ITER_STATE(text);
@@ -801,111 +730,97 @@ static int64_t _find(Text_t text, Text_t pattern, int64_t first, int64_t last, i
int64_t m = match(text, i, pattern, 0, captures, 0);
if (m >= 0) {
- if (match_length)
- *match_length = m;
+ if (match_length) *match_length = m;
return i;
}
}
- if (match_length)
- *match_length = -1;
+ if (match_length) *match_length = -1;
return -1;
}
-static OptionalPatternMatch find(Text_t text, Text_t pattern, Int_t from_index)
-{
+static OptionalPatternMatch find(Text_t text, Text_t pattern, Int_t from_index) {
int64_t first = Int64$from_int(from_index, false);
if (first == 0) fail("Invalid index: 0");
if (first < 0) first = text.length + first + 1;
- if (first > text.length || first < 1)
- return NONE_MATCH;
+ if (first > text.length || first < 1) return NONE_MATCH;
capture_t captures[MAX_BACKREFS] = {};
int64_t len = 0;
- int64_t found = _find(text, pattern, first-1, text.length-1, &len, captures);
- if (found == -1)
- return NONE_MATCH;
+ int64_t found = _find(text, pattern, first - 1, text.length - 1, &len, captures);
+ if (found == -1) return NONE_MATCH;
List_t capture_list = {};
for (int i = 0; captures[i].occupied; i++) {
- Text_t capture = Text$slice(text, I(captures[i].index+1), I(captures[i].index+captures[i].length));
+ Text_t capture = Text$slice(text, I(captures[i].index + 1), I(captures[i].index + captures[i].length));
List$insert(&capture_list, &capture, I(0), sizeof(Text_t));
}
return (OptionalPatternMatch){
- .text=Text$slice(text, I(found+1), I(found+len)),
- .index=I(found+1),
- .captures=capture_list,
+ .text = Text$slice(text, I(found + 1), I(found + len)),
+ .index = I(found + 1),
+ .captures = capture_list,
};
}
-PUREFUNC static bool Pattern$has(Text_t text, Text_t pattern)
-{
+PUREFUNC static bool Pattern$has(Text_t text, Text_t pattern) {
if (Text$starts_with(pattern, Text("{start}"), &pattern)) {
int64_t m = match(text, 0, pattern, 0, NULL, 0);
return m >= 0;
} else if (Text$ends_with(text, Text("{end}"), NULL)) {
- for (int64_t i = text.length-1; i >= 0; i--) {
+ for (int64_t i = text.length - 1; i >= 0; i--) {
int64_t match_len = match(text, i, pattern, 0, NULL, 0);
- if (match_len >= 0 && i + match_len == text.length)
- return true;
+ if (match_len >= 0 && i + match_len == text.length) return true;
}
return false;
} else {
- int64_t found = _find(text, pattern, 0, text.length-1, NULL, NULL);
+ int64_t found = _find(text, pattern, 0, text.length - 1, NULL, NULL);
return (found >= 0);
}
}
-static bool Pattern$matches(Text_t text, Text_t pattern)
-{
+static bool Pattern$matches(Text_t text, Text_t pattern) {
capture_t captures[MAX_BACKREFS] = {};
int64_t match_len = match(text, 0, pattern, 0, NULL, 0);
return (match_len == text.length);
}
-static bool Pattern$match_at(Text_t text, Text_t pattern, Int_t pos, PatternMatch *dest)
-{
+static bool Pattern$match_at(Text_t text, Text_t pattern, Int_t pos, PatternMatch *dest) {
int64_t start = Int64$from_int(pos, false) - 1;
capture_t captures[MAX_BACKREFS] = {};
int64_t match_len = match(text, start, pattern, 0, captures, 0);
- if (match_len < 0)
- return false;
+ if (match_len < 0) return false;
List_t capture_list = {};
for (int i = 0; captures[i].occupied; i++) {
- Text_t capture = Text$slice(text, I(captures[i].index+1), I(captures[i].index+captures[i].length));
+ Text_t capture = Text$slice(text, I(captures[i].index + 1), I(captures[i].index + captures[i].length));
List$insert(&capture_list, &capture, I(0), sizeof(Text_t));
}
- dest->text = Text$slice(text, I(start+1), I(start+match_len));
- dest->index = I(start+1);
+ dest->text = Text$slice(text, I(start + 1), I(start + match_len));
+ dest->index = I(start + 1);
dest->captures = capture_list;
return true;
}
-static OptionalList_t Pattern$captures(Text_t text, Text_t pattern)
-{
+static OptionalList_t Pattern$captures(Text_t text, Text_t pattern) {
capture_t captures[MAX_BACKREFS] = {};
int64_t match_len = match(text, 0, pattern, 0, captures, 0);
- if (match_len != text.length)
- return NONE_LIST;
+ if (match_len != text.length) return NONE_LIST;
List_t capture_list = {};
for (int i = 0; captures[i].occupied; i++) {
- Text_t capture = Text$slice(text, I(captures[i].index+1), I(captures[i].index+captures[i].length));
+ Text_t capture = Text$slice(text, I(captures[i].index + 1), I(captures[i].index + captures[i].length));
List$insert(&capture_list, &capture, I(0), sizeof(Text_t));
}
return capture_list;
}
-static List_t Pattern$find_all(Text_t text, Text_t pattern)
-{
+static List_t Pattern$find_all(Text_t text, Text_t pattern) {
if (pattern.length == 0) // special case
- return (List_t){.length=0};
+ return (List_t){.length = 0};
List_t matches = {};
- for (int64_t i = 1; ; ) {
+ for (int64_t i = 1;;) {
OptionalPatternMatch m = find(text, pattern, I(i));
- if (m.is_none)
- break;
+ if (m.is_none) break;
i = Int64$from_int(m.index, false) + m.text.length;
List$insert(&matches, &m, I_small(0), sizeof(PatternMatch));
}
@@ -918,41 +833,35 @@ typedef struct {
Text_t pattern;
} match_iter_state_t;
-static OptionalPatternMatch next_match(match_iter_state_t *state)
-{
- if (Int64$from_int(state->i, false) > state->state.stack[0].text.length)
- return NONE_MATCH;
+static OptionalPatternMatch next_match(match_iter_state_t *state) {
+ if (Int64$from_int(state->i, false) > state->state.stack[0].text.length) return NONE_MATCH;
OptionalPatternMatch m = find(state->state.stack[0].text, state->pattern, state->i);
if (m.is_none) // No match
state->i = I(state->state.stack[0].text.length + 1);
- else
- state->i = Int$plus(m.index, I(MAX(1, m.text.length)));
+ else state->i = Int$plus(m.index, I(MAX(1, m.text.length)));
return m;
}
-static Closure_t Pattern$by_match(Text_t text, Text_t pattern)
-{
+static Closure_t Pattern$by_match(Text_t text, Text_t pattern) {
return (Closure_t){
- .fn=(void*)next_match,
- .userdata=new(match_iter_state_t, .state=NEW_TEXT_ITER_STATE(text), .i=I_small(1), .pattern=pattern),
+ .fn = (void *)next_match,
+ .userdata = new (match_iter_state_t, .state = NEW_TEXT_ITER_STATE(text), .i = I_small(1), .pattern = pattern),
};
}
-static Text_t apply_backrefs(Text_t text, List_t recursive_replacements, Text_t replacement, Text_t backref_pat, capture_t *captures)
-{
- if (backref_pat.length == 0)
- return replacement;
+static Text_t apply_backrefs(Text_t text, List_t recursive_replacements, Text_t replacement, Text_t backref_pat,
+ capture_t *captures) {
+ if (backref_pat.length == 0) return replacement;
int32_t first_grapheme = Text$get_grapheme(backref_pat, 0);
- bool find_first = (first_grapheme != '{'
- && !uc_is_property((ucs4_t)first_grapheme, UC_PROPERTY_QUOTATION_MARK)
+ bool find_first = (first_grapheme != '{' && !uc_is_property((ucs4_t)first_grapheme, UC_PROPERTY_QUOTATION_MARK)
&& !uc_is_property((ucs4_t)first_grapheme, UC_PROPERTY_PAIRED_PUNCTUATION));
Text_t ret = Text("");
TextIter_t replacement_state = NEW_TEXT_ITER_STATE(replacement);
int64_t nonmatching_pos = 0;
- for (int64_t pos = 0; pos < replacement.length; ) {
+ for (int64_t pos = 0; pos < replacement.length;) {
// Optimization: quickly skip ahead to first char in the backref pattern:
if (find_first) {
while (pos < replacement.length && Text$get_grapheme_fast(&replacement_state, pos) != first_grapheme)
@@ -971,22 +880,23 @@ static Text_t apply_backrefs(Text_t text, List_t recursive_replacements, Text_t
pos += 1;
continue;
}
- if (backref < 0 || backref > 9) fail("Invalid backref index: ", backref, " (only 0-", MAX_BACKREFS-1, " are allowed)");
+ if (backref < 0 || backref > 9)
+ fail("Invalid backref index: ", backref, " (only 0-", MAX_BACKREFS - 1, " are allowed)");
backref_len = (after_backref - pos);
if (Text$get_grapheme_fast(&replacement_state, pos + backref_len) == ';')
backref_len += 1; // skip optional semicolon
- if (!captures[backref].occupied)
- fail("There is no capture number ", backref, "!");
+ if (!captures[backref].occupied) fail("There is no capture number ", backref, "!");
- Text_t backref_text = Text$slice(text, I(captures[backref].index+1), I(captures[backref].index + captures[backref].length));
+ Text_t backref_text =
+ Text$slice(text, I(captures[backref].index + 1), I(captures[backref].index + captures[backref].length));
if (captures[backref].recursive && recursive_replacements.length > 0)
backref_text = replace_list(backref_text, recursive_replacements, backref_pat, true);
if (pos > nonmatching_pos) {
- Text_t before_slice = Text$slice(replacement, I(nonmatching_pos+1), I(pos));
+ Text_t before_slice = Text$slice(replacement, I(nonmatching_pos + 1), I(pos));
ret = Text$concat(ret, before_slice, backref_text);
} else {
ret = Text$concat(ret, backref_text);
@@ -996,31 +906,29 @@ static Text_t apply_backrefs(Text_t text, List_t recursive_replacements, Text_t
nonmatching_pos = pos;
}
if (nonmatching_pos < replacement.length) {
- Text_t last_slice = Text$slice(replacement, I(nonmatching_pos+1), I(replacement.length));
+ Text_t last_slice = Text$slice(replacement, I(nonmatching_pos + 1), I(replacement.length));
ret = Text$concat(ret, last_slice);
}
return ret;
}
-static Text_t Pattern$replace(Text_t text, Text_t pattern, Text_t replacement, Text_t backref_pat, bool recursive)
-{
+static Text_t Pattern$replace(Text_t text, Text_t pattern, Text_t replacement, Text_t backref_pat, bool recursive) {
Text_t ret = EMPTY_TEXT;
int32_t first_grapheme = Text$get_grapheme(pattern, 0);
- bool find_first = (first_grapheme != '{'
- && !uc_is_property((ucs4_t)first_grapheme, UC_PROPERTY_QUOTATION_MARK)
+ bool find_first = (first_grapheme != '{' && !uc_is_property((ucs4_t)first_grapheme, UC_PROPERTY_QUOTATION_MARK)
&& !uc_is_property((ucs4_t)first_grapheme, UC_PROPERTY_PAIRED_PUNCTUATION));
Text_t entries[2] = {pattern, replacement};
List_t replacements = {
- .data=entries,
- .length=1,
- .stride=sizeof(entries),
+ .data = entries,
+ .length = 1,
+ .stride = sizeof(entries),
};
TextIter_t text_state = NEW_TEXT_ITER_STATE(text);
int64_t nonmatching_pos = 0;
- for (int64_t pos = 0; pos < text.length; ) {
+ for (int64_t pos = 0; pos < text.length;) {
// Optimization: quickly skip ahead to first char in pattern:
if (find_first) {
while (pos < text.length && Text$get_grapheme_fast(&text_state, pos) != first_grapheme)
@@ -1034,13 +942,16 @@ static Text_t Pattern$replace(Text_t text, Text_t pattern, Text_t replacement, T
continue;
}
captures[0] = (capture_t){
- .index = pos, .length = match_len,
- .occupied = true, .recursive = false,
+ .index = pos,
+ .length = match_len,
+ .occupied = true,
+ .recursive = false,
};
- Text_t replacement_text = apply_backrefs(text, recursive ? replacements : (List_t){}, replacement, backref_pat, captures);
+ Text_t replacement_text =
+ apply_backrefs(text, recursive ? replacements : (List_t){}, replacement, backref_pat, captures);
if (pos > nonmatching_pos) {
- Text_t before_slice = Text$slice(text, I(nonmatching_pos+1), I(pos));
+ Text_t before_slice = Text$slice(text, I(nonmatching_pos + 1), I(pos));
ret = Text$concat(ret, before_slice, replacement_text);
} else {
ret = Text$concat(ret, replacement_text);
@@ -1049,44 +960,39 @@ static Text_t Pattern$replace(Text_t text, Text_t pattern, Text_t replacement, T
pos += MAX(match_len, 1);
}
if (nonmatching_pos < text.length) {
- Text_t last_slice = Text$slice(text, I(nonmatching_pos+1), I(text.length));
+ Text_t last_slice = Text$slice(text, I(nonmatching_pos + 1), I(text.length));
ret = Text$concat(ret, last_slice);
}
return ret;
}
-static Text_t Pattern$trim(Text_t text, Text_t pattern, bool trim_left, bool trim_right)
-{
- int64_t first = 0, last = text.length-1;
+static Text_t Pattern$trim(Text_t text, Text_t pattern, bool trim_left, bool trim_right) {
+ int64_t first = 0, last = text.length - 1;
if (trim_left) {
int64_t match_len = match(text, 0, pattern, 0, NULL, 0);
- if (match_len > 0)
- first = match_len;
+ if (match_len > 0) first = match_len;
}
if (trim_right) {
- for (int64_t i = text.length-1; i >= first; i--) {
+ for (int64_t i = text.length - 1; i >= first; i--) {
int64_t match_len = match(text, i, pattern, 0, NULL, 0);
- if (match_len > 0 && i + match_len == text.length)
- last = i-1;
+ if (match_len > 0 && i + match_len == text.length) last = i - 1;
}
}
- return Text$slice(text, I(first+1), I(last+1));
+ return Text$slice(text, I(first + 1), I(last + 1));
}
-static Text_t Pattern$map(Text_t text, Text_t pattern, Closure_t fn, bool recursive)
-{
+static Text_t Pattern$map(Text_t text, Text_t pattern, Closure_t fn, bool recursive) {
Text_t ret = EMPTY_TEXT;
int32_t first_grapheme = Text$get_grapheme(pattern, 0);
- bool find_first = (first_grapheme != '{'
- && !uc_is_property((ucs4_t)first_grapheme, UC_PROPERTY_QUOTATION_MARK)
+ bool find_first = (first_grapheme != '{' && !uc_is_property((ucs4_t)first_grapheme, UC_PROPERTY_QUOTATION_MARK)
&& !uc_is_property((ucs4_t)first_grapheme, UC_PROPERTY_PAIRED_PUNCTUATION));
TextIter_t text_state = NEW_TEXT_ITER_STATE(text);
int64_t nonmatching_pos = 0;
- Text_t (*text_mapper)(PatternMatch, void*) = fn.fn;
+ Text_t (*text_mapper)(PatternMatch, void *) = fn.fn;
for (int64_t pos = 0; pos < text.length; pos++) {
// Optimization: quickly skip ahead to first char in pattern:
if (find_first) {
@@ -1099,20 +1005,19 @@ static Text_t Pattern$map(Text_t text, Text_t pattern, Closure_t fn, bool recurs
if (match_len < 0) continue;
PatternMatch m = {
- .text=Text$slice(text, I(pos+1), I(pos+match_len)),
- .index=I(pos+1),
- .captures={},
+ .text = Text$slice(text, I(pos + 1), I(pos + match_len)),
+ .index = I(pos + 1),
+ .captures = {},
};
for (int i = 0; captures[i].occupied; i++) {
- Text_t capture = Text$slice(text, I(captures[i].index+1), I(captures[i].index+captures[i].length));
- if (recursive)
- capture = Pattern$map(capture, pattern, fn, recursive);
+ Text_t capture = Text$slice(text, I(captures[i].index + 1), I(captures[i].index + captures[i].length));
+ if (recursive) capture = Pattern$map(capture, pattern, fn, recursive);
List$insert(&m.captures, &capture, I(0), sizeof(Text_t));
}
Text_t replacement = text_mapper(m, fn.userdata);
if (pos > nonmatching_pos) {
- Text_t before_slice = Text$slice(text, I(nonmatching_pos+1), I(pos));
+ Text_t before_slice = Text$slice(text, I(nonmatching_pos + 1), I(pos));
ret = Text$concat(ret, before_slice, replacement);
} else {
ret = Text$concat(ret, replacement);
@@ -1121,21 +1026,19 @@ static Text_t Pattern$map(Text_t text, Text_t pattern, Closure_t fn, bool recurs
pos += (match_len - 1);
}
if (nonmatching_pos < text.length) {
- Text_t last_slice = Text$slice(text, I(nonmatching_pos+1), I(text.length));
+ Text_t last_slice = Text$slice(text, I(nonmatching_pos + 1), I(text.length));
ret = Text$concat(ret, last_slice);
}
return ret;
}
-static void Pattern$each(Text_t text, Text_t pattern, Closure_t fn, bool recursive)
-{
+static void Pattern$each(Text_t text, Text_t pattern, Closure_t fn, bool recursive) {
int32_t first_grapheme = Text$get_grapheme(pattern, 0);
- bool find_first = (first_grapheme != '{'
- && !uc_is_property((ucs4_t)first_grapheme, UC_PROPERTY_QUOTATION_MARK)
+ bool find_first = (first_grapheme != '{' && !uc_is_property((ucs4_t)first_grapheme, UC_PROPERTY_QUOTATION_MARK)
&& !uc_is_property((ucs4_t)first_grapheme, UC_PROPERTY_PAIRED_PUNCTUATION));
TextIter_t text_state = NEW_TEXT_ITER_STATE(text);
- void (*action)(PatternMatch, void*) = fn.fn;
+ void (*action)(PatternMatch, void *) = fn.fn;
for (int64_t pos = 0; pos < text.length; pos++) {
// Optimization: quickly skip ahead to first char in pattern:
if (find_first) {
@@ -1148,14 +1051,13 @@ static void Pattern$each(Text_t text, Text_t pattern, Closure_t fn, bool recursi
if (match_len < 0) continue;
PatternMatch m = {
- .text=Text$slice(text, I(pos+1), I(pos+match_len)),
- .index=I(pos+1),
- .captures={},
+ .text = Text$slice(text, I(pos + 1), I(pos + match_len)),
+ .index = I(pos + 1),
+ .captures = {},
};
for (int i = 0; captures[i].occupied; i++) {
- Text_t capture = Text$slice(text, I(captures[i].index+1), I(captures[i].index+captures[i].length));
- if (recursive)
- Pattern$each(capture, pattern, fn, recursive);
+ Text_t capture = Text$slice(text, I(captures[i].index + 1), I(captures[i].index + captures[i].length));
+ if (recursive) Pattern$each(capture, pattern, fn, recursive);
List$insert(&m.captures, &capture, I(0), sizeof(Text_t));
}
@@ -1164,17 +1066,16 @@ static void Pattern$each(Text_t text, Text_t pattern, Closure_t fn, bool recursi
}
}
-Text_t replace_list(Text_t text, List_t replacements, Text_t backref_pat, bool recursive)
-{
+Text_t replace_list(Text_t text, List_t replacements, Text_t backref_pat, bool recursive) {
if (replacements.length == 0) return text;
Text_t ret = EMPTY_TEXT;
int64_t nonmatch_pos = 0;
- for (int64_t pos = 0; pos < text.length; ) {
+ for (int64_t pos = 0; pos < text.length;) {
// Find the first matching pattern at this position:
for (int64_t i = 0; i < replacements.length; i++) {
- Text_t pattern = *(Text_t*)(replacements.data + i*replacements.stride);
+ Text_t pattern = *(Text_t *)(replacements.data + i * replacements.stride);
capture_t captures[MAX_BACKREFS] = {};
int64_t len = match(text, pos, pattern, 0, captures, 1);
if (len < 0) continue;
@@ -1183,13 +1084,14 @@ Text_t replace_list(Text_t text, List_t replacements, Text_t backref_pat, bool r
// If we skipped over some non-matching text before finding a match, insert it here:
if (pos > nonmatch_pos) {
- Text_t before_slice = Text$slice(text, I(nonmatch_pos+1), I(pos));
+ Text_t before_slice = Text$slice(text, I(nonmatch_pos + 1), I(pos));
ret = Text$concat(ret, before_slice);
}
// Concatenate the replacement:
- Text_t replacement = *(Text_t*)(replacements.data + i*replacements.stride + sizeof(Text_t));
- Text_t replacement_text = apply_backrefs(text, recursive ? replacements : (List_t){}, replacement, backref_pat, captures);
+ Text_t replacement = *(Text_t *)(replacements.data + i * replacements.stride + sizeof(Text_t));
+ Text_t replacement_text =
+ apply_backrefs(text, recursive ? replacements : (List_t){}, replacement, backref_pat, captures);
ret = Text$concat(ret, replacement_text);
pos += MAX(len, 1);
nonmatch_pos = pos;
@@ -1197,26 +1099,24 @@ Text_t replace_list(Text_t text, List_t replacements, Text_t backref_pat, bool r
}
pos += 1;
- next_pos:
+ next_pos:
continue;
}
if (nonmatch_pos <= text.length) {
- Text_t last_slice = Text$slice(text, I(nonmatch_pos+1), I(text.length));
+ Text_t last_slice = Text$slice(text, I(nonmatch_pos + 1), I(text.length));
ret = Text$concat(ret, last_slice);
}
return ret;
}
-static Text_t Pattern$replace_all(Text_t text, Table_t replacements, Text_t backref_pat, bool recursive)
-{
+static Text_t Pattern$replace_all(Text_t text, Table_t replacements, Text_t backref_pat, bool recursive) {
return replace_list(text, replacements.entries, backref_pat, recursive);
}
-static List_t Pattern$split(Text_t text, Text_t pattern)
-{
+static List_t Pattern$split(Text_t text, Text_t pattern) {
if (text.length == 0) // special case
- return (List_t){.length=0};
+ return (List_t){.length = 0};
if (pattern.length == 0) // special case
return Text$clusters(text);
@@ -1226,16 +1126,15 @@ static List_t Pattern$split(Text_t text, Text_t pattern)
int64_t i = 0;
for (;;) {
int64_t len = 0;
- int64_t found = _find(text, pattern, i, text.length-1, &len, NULL);
- if (found == i && len == 0)
- found = _find(text, pattern, i + 1, text.length-1, &len, NULL);
+ int64_t found = _find(text, pattern, i, text.length - 1, &len, NULL);
+ if (found == i && len == 0) found = _find(text, pattern, i + 1, text.length - 1, &len, NULL);
if (found < 0) break;
- Text_t chunk = Text$slice(text, I(i+1), I(found));
+ Text_t chunk = Text$slice(text, I(i + 1), I(found));
List$insert(&chunks, &chunk, I_small(0), sizeof(Text_t));
i = MAX(found + len, i + 1);
}
- Text_t last_chunk = Text$slice(text, I(i+1), I(text.length));
+ Text_t last_chunk = Text$slice(text, I(i + 1), I(text.length));
List$insert(&chunks, &last_chunk, I_small(0), sizeof(Text_t));
return chunks;
@@ -1247,8 +1146,7 @@ typedef struct {
Text_t pattern;
} split_iter_state_t;
-static OptionalText_t next_split(split_iter_state_t *state)
-{
+static OptionalText_t next_split(split_iter_state_t *state) {
Text_t text = state->state.stack[0].text;
if (state->i >= text.length) {
if (state->pattern.length > 0 && state->i == text.length) { // special case
@@ -1259,37 +1157,34 @@ static OptionalText_t next_split(split_iter_state_t *state)
}
if (state->pattern.length == 0) { // special case
- Text_t ret = Text$cluster(text, I(state->i+1));
+ Text_t ret = Text$cluster(text, I(state->i + 1));
state->i += 1;
return ret;
}
int64_t start = state->i;
int64_t len = 0;
- int64_t found = _find(text, state->pattern, start, text.length-1, &len, NULL);
+ int64_t found = _find(text, state->pattern, start, text.length - 1, &len, NULL);
- if (found == start && len == 0)
- found = _find(text, state->pattern, start + 1, text.length-1, &len, NULL);
+ if (found == start && len == 0) found = _find(text, state->pattern, start + 1, text.length - 1, &len, NULL);
if (found >= 0) {
state->i = MAX(found + len, state->i + 1);
- return Text$slice(text, I(start+1), I(found));
+ return Text$slice(text, I(start + 1), I(found));
} else {
state->i = state->state.stack[0].text.length + 1;
- return Text$slice(text, I(start+1), I(text.length));
+ return Text$slice(text, I(start + 1), I(text.length));
}
}
-static Closure_t Pattern$by_split(Text_t text, Text_t pattern)
-{
+static Closure_t Pattern$by_split(Text_t text, Text_t pattern) {
return (Closure_t){
- .fn=(void*)next_split,
- .userdata=new(split_iter_state_t, .state=NEW_TEXT_ITER_STATE(text), .i=0, .pattern=pattern),
+ .fn = (void *)next_split,
+ .userdata = new (split_iter_state_t, .state = NEW_TEXT_ITER_STATE(text), .i = 0, .pattern = pattern),
};
}
-static Text_t Pattern$escape_text(Text_t text)
-{
+static Text_t Pattern$escape_text(Text_t text) {
// TODO: optimize for spans of non-escaped text
Text_t ret = EMPTY_TEXT;
TextIter_t state = NEW_TEXT_ITER_STATE(text);
@@ -1297,23 +1192,21 @@ static Text_t Pattern$escape_text(Text_t text)
uint32_t g = Text$get_main_grapheme_fast(&state, i);
if (g == '{') {
ret = Text$concat(ret, Text("{1{}"));
- } else if (g == '?'
- || uc_is_property_quotation_mark(g)
+ } else if (g == '?' || uc_is_property_quotation_mark(g)
|| (uc_is_property_paired_punctuation(g) && uc_is_property_left_of_pair(g))) {
- ret = Text$concat(ret, Text("{1"), Text$slice(text, I(i+1), I(i+1)), Text("}"));
+ ret = Text$concat(ret, Text("{1"), Text$slice(text, I(i + 1), I(i + 1)), Text("}"));
} else {
- ret = Text$concat(ret, Text$slice(text, I(i+1), I(i+1)));
+ ret = Text$concat(ret, Text$slice(text, I(i + 1), I(i + 1)));
}
}
return ret;
}
-static Text_t Pattern$as_text(const void *obj, bool colorize, const TypeInfo_t *info)
-{
+static Text_t Pattern$as_text(const void *obj, bool colorize, const TypeInfo_t *info) {
(void)info;
if (!obj) return Text("Pattern");
- Text_t pat = *(Text_t*)obj;
+ Text_t pat = *(Text_t *)obj;
Text_t quote = Pattern$has(pat, Text("/")) && !Pattern$has(pat, Text("|")) ? Text("|") : Text("/");
return Text$concat(colorize ? Text("\x1b[1m$\033[m") : Text("$"), Text$quoted(pat, colorize, quote));
}
diff --git a/lib/random/chacha.h b/lib/random/chacha.h
index b803c24a..a98c0b87 100644
--- a/lib/random/chacha.h
+++ b/lib/random/chacha.h
@@ -11,9 +11,8 @@ Public domain.
typedef unsigned char u8;
typedef unsigned int u32;
-typedef struct
-{
- u32 input[16]; /* could be compressed */
+typedef struct {
+ u32 input[16]; /* could be compressed */
} chacha_ctx;
#define KEYSZ 32
@@ -25,172 +24,167 @@ typedef struct
#define U8V(v) ((u8)(v) & U8C(0xFF))
#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF))
-#define ROTL32(v, n) \
- (U32V((v) << (n)) | ((v) >> (32 - (n))))
+#define ROTL32(v, n) (U32V((v) << (n)) | ((v) >> (32 - (n))))
-#define U8TO32_LITTLE(p) \
- (((u32)((p)[0]) ) | \
- ((u32)((p)[1]) << 8) | \
- ((u32)((p)[2]) << 16) | \
- ((u32)((p)[3]) << 24))
+#define U8TO32_LITTLE(p) (((u32)((p)[0])) | ((u32)((p)[1]) << 8) | ((u32)((p)[2]) << 16) | ((u32)((p)[3]) << 24))
-#define U32TO8_LITTLE(p, v) \
- do { \
- (p)[0] = U8V((v) ); \
- (p)[1] = U8V((v) >> 8); \
- (p)[2] = U8V((v) >> 16); \
- (p)[3] = U8V((v) >> 24); \
- } while (0)
+#define U32TO8_LITTLE(p, v) \
+ do { \
+ (p)[0] = U8V((v)); \
+ (p)[1] = U8V((v) >> 8); \
+ (p)[2] = U8V((v) >> 16); \
+ (p)[3] = U8V((v) >> 24); \
+ } while (0)
#define ROTATE(v, c) (ROTL32(v, c))
#define XOR(v, w) ((v) ^ (w))
#define PLUS(v, w) (U32V((v) + (w)))
#define PLUSONE(v) (PLUS((v), 1))
-#define QUARTERROUND(a, b, c, d) \
- a = PLUS(a, b); d = ROTATE(XOR(d, a), 16); \
- c = PLUS(c, d); b = ROTATE(XOR(b, c), 12); \
- a = PLUS(a, b); d = ROTATE(XOR(d, a), 8); \
- c = PLUS(c, d); b = ROTATE(XOR(b, c), 7);
+#define QUARTERROUND(a, b, c, d) \
+ a = PLUS(a, b); \
+ d = ROTATE(XOR(d, a), 16); \
+ c = PLUS(c, d); \
+ b = ROTATE(XOR(b, c), 12); \
+ a = PLUS(a, b); \
+ d = ROTATE(XOR(d, a), 8); \
+ c = PLUS(c, d); \
+ b = ROTATE(XOR(b, c), 7);
static const char sigma[16] = "expand 32-byte k";
-static void
-chacha_keysetup(chacha_ctx *chacha, const u8 *k)
-{
- chacha->input[0] = U8TO32_LITTLE(sigma + 0);
- chacha->input[1] = U8TO32_LITTLE(sigma + 4);
- chacha->input[2] = U8TO32_LITTLE(sigma + 8);
- chacha->input[3] = U8TO32_LITTLE(sigma + 12);
- chacha->input[4] = U8TO32_LITTLE(k + 0);
- chacha->input[5] = U8TO32_LITTLE(k + 4);
- chacha->input[6] = U8TO32_LITTLE(k + 8);
- chacha->input[7] = U8TO32_LITTLE(k + 12);
- chacha->input[8] = U8TO32_LITTLE(k + 16);
- chacha->input[9] = U8TO32_LITTLE(k + 20);
- chacha->input[10] = U8TO32_LITTLE(k + 24);
- chacha->input[11] = U8TO32_LITTLE(k + 28);
+static void chacha_keysetup(chacha_ctx *chacha, const u8 *k) {
+ chacha->input[0] = U8TO32_LITTLE(sigma + 0);
+ chacha->input[1] = U8TO32_LITTLE(sigma + 4);
+ chacha->input[2] = U8TO32_LITTLE(sigma + 8);
+ chacha->input[3] = U8TO32_LITTLE(sigma + 12);
+ chacha->input[4] = U8TO32_LITTLE(k + 0);
+ chacha->input[5] = U8TO32_LITTLE(k + 4);
+ chacha->input[6] = U8TO32_LITTLE(k + 8);
+ chacha->input[7] = U8TO32_LITTLE(k + 12);
+ chacha->input[8] = U8TO32_LITTLE(k + 16);
+ chacha->input[9] = U8TO32_LITTLE(k + 20);
+ chacha->input[10] = U8TO32_LITTLE(k + 24);
+ chacha->input[11] = U8TO32_LITTLE(k + 28);
}
-static void
-chacha_ivsetup(chacha_ctx *chacha, const u8 *iv)
-{
- chacha->input[12] = 0;
- chacha->input[13] = 0;
- chacha->input[14] = U8TO32_LITTLE(iv + 0);
- chacha->input[15] = U8TO32_LITTLE(iv + 4);
+static void chacha_ivsetup(chacha_ctx *chacha, const u8 *iv) {
+ chacha->input[12] = 0;
+ chacha->input[13] = 0;
+ chacha->input[14] = U8TO32_LITTLE(iv + 0);
+ chacha->input[15] = U8TO32_LITTLE(iv + 4);
}
-static void
-chacha_encrypt_bytes(chacha_ctx *chacha, const u8 *m, u8 *c, u32 bytes)
-{
- u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
- u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
- u8 *ctarget = (u8*)0;
- u8 tmp[64];
- unsigned int i;
-
- if (!bytes) return;
-
- j0 = chacha->input[0];
- j1 = chacha->input[1];
- j2 = chacha->input[2];
- j3 = chacha->input[3];
- j4 = chacha->input[4];
- j5 = chacha->input[5];
- j6 = chacha->input[6];
- j7 = chacha->input[7];
- j8 = chacha->input[8];
- j9 = chacha->input[9];
- j10 = chacha->input[10];
- j11 = chacha->input[11];
- j12 = chacha->input[12];
- j13 = chacha->input[13];
- j14 = chacha->input[14];
- j15 = chacha->input[15];
-
- for (;;) {
- if (bytes < 64) {
- for (i = 0;i < bytes;++i) tmp[i] = m[i];
- m = tmp;
- ctarget = c;
- c = tmp;
+static void chacha_encrypt_bytes(chacha_ctx *chacha, const u8 *m, u8 *c, u32 bytes) {
+ u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
+ u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
+ u8 *ctarget = (u8 *)0;
+ u8 tmp[64];
+ unsigned int i;
+
+ if (!bytes) return;
+
+ j0 = chacha->input[0];
+ j1 = chacha->input[1];
+ j2 = chacha->input[2];
+ j3 = chacha->input[3];
+ j4 = chacha->input[4];
+ j5 = chacha->input[5];
+ j6 = chacha->input[6];
+ j7 = chacha->input[7];
+ j8 = chacha->input[8];
+ j9 = chacha->input[9];
+ j10 = chacha->input[10];
+ j11 = chacha->input[11];
+ j12 = chacha->input[12];
+ j13 = chacha->input[13];
+ j14 = chacha->input[14];
+ j15 = chacha->input[15];
+
+ for (;;) {
+ if (bytes < 64) {
+ for (i = 0; i < bytes; ++i)
+ tmp[i] = m[i];
+ m = tmp;
+ ctarget = c;
+ c = tmp;
+ }
+ x0 = j0;
+ x1 = j1;
+ x2 = j2;
+ x3 = j3;
+ x4 = j4;
+ x5 = j5;
+ x6 = j6;
+ x7 = j7;
+ x8 = j8;
+ x9 = j9;
+ x10 = j10;
+ x11 = j11;
+ x12 = j12;
+ x13 = j13;
+ x14 = j14;
+ x15 = j15;
+ for (i = 20; i > 0; i -= 2) {
+ QUARTERROUND(x0, x4, x8, x12)
+ QUARTERROUND(x1, x5, x9, x13)
+ QUARTERROUND(x2, x6, x10, x14)
+ QUARTERROUND(x3, x7, x11, x15)
+ QUARTERROUND(x0, x5, x10, x15)
+ QUARTERROUND(x1, x6, x11, x12)
+ QUARTERROUND(x2, x7, x8, x13)
+ QUARTERROUND(x3, x4, x9, x14)
+ }
+ x0 = PLUS(x0, j0);
+ x1 = PLUS(x1, j1);
+ x2 = PLUS(x2, j2);
+ x3 = PLUS(x3, j3);
+ x4 = PLUS(x4, j4);
+ x5 = PLUS(x5, j5);
+ x6 = PLUS(x6, j6);
+ x7 = PLUS(x7, j7);
+ x8 = PLUS(x8, j8);
+ x9 = PLUS(x9, j9);
+ x10 = PLUS(x10, j10);
+ x11 = PLUS(x11, j11);
+ x12 = PLUS(x12, j12);
+ x13 = PLUS(x13, j13);
+ x14 = PLUS(x14, j14);
+ x15 = PLUS(x15, j15);
+
+ j12 = PLUSONE(j12);
+ if (!j12) {
+ j13 = PLUSONE(j13);
+ /* stopping at 2^70 bytes per nonce is user's responsibility */
+ }
+
+ U32TO8_LITTLE(c + 0, x0);
+ U32TO8_LITTLE(c + 4, x1);
+ U32TO8_LITTLE(c + 8, x2);
+ U32TO8_LITTLE(c + 12, x3);
+ U32TO8_LITTLE(c + 16, x4);
+ U32TO8_LITTLE(c + 20, x5);
+ U32TO8_LITTLE(c + 24, x6);
+ U32TO8_LITTLE(c + 28, x7);
+ U32TO8_LITTLE(c + 32, x8);
+ U32TO8_LITTLE(c + 36, x9);
+ U32TO8_LITTLE(c + 40, x10);
+ U32TO8_LITTLE(c + 44, x11);
+ U32TO8_LITTLE(c + 48, x12);
+ U32TO8_LITTLE(c + 52, x13);
+ U32TO8_LITTLE(c + 56, x14);
+ U32TO8_LITTLE(c + 60, x15);
+
+ if (bytes <= 64) {
+ if (bytes < 64) {
+ for (i = 0; i < bytes; ++i)
+ ctarget[i] = c[i];
+ }
+ chacha->input[12] = j12;
+ chacha->input[13] = j13;
+ return;
+ }
+ bytes -= 64;
+ c += 64;
}
- x0 = j0;
- x1 = j1;
- x2 = j2;
- x3 = j3;
- x4 = j4;
- x5 = j5;
- x6 = j6;
- x7 = j7;
- x8 = j8;
- x9 = j9;
- x10 = j10;
- x11 = j11;
- x12 = j12;
- x13 = j13;
- x14 = j14;
- x15 = j15;
- for (i = 20;i > 0;i -= 2) {
- QUARTERROUND( x0, x4, x8, x12)
- QUARTERROUND( x1, x5, x9, x13)
- QUARTERROUND( x2, x6, x10, x14)
- QUARTERROUND( x3, x7, x11, x15)
- QUARTERROUND( x0, x5, x10, x15)
- QUARTERROUND( x1, x6, x11, x12)
- QUARTERROUND( x2, x7, x8, x13)
- QUARTERROUND( x3, x4, x9, x14)
- }
- x0 = PLUS(x0, j0);
- x1 = PLUS(x1, j1);
- x2 = PLUS(x2, j2);
- x3 = PLUS(x3, j3);
- x4 = PLUS(x4, j4);
- x5 = PLUS(x5, j5);
- x6 = PLUS(x6, j6);
- x7 = PLUS(x7, j7);
- x8 = PLUS(x8, j8);
- x9 = PLUS(x9, j9);
- x10 = PLUS(x10, j10);
- x11 = PLUS(x11, j11);
- x12 = PLUS(x12, j12);
- x13 = PLUS(x13, j13);
- x14 = PLUS(x14, j14);
- x15 = PLUS(x15, j15);
-
- j12 = PLUSONE(j12);
- if (!j12) {
- j13 = PLUSONE(j13);
- /* stopping at 2^70 bytes per nonce is user's responsibility */
- }
-
- U32TO8_LITTLE(c + 0, x0);
- U32TO8_LITTLE(c + 4, x1);
- U32TO8_LITTLE(c + 8, x2);
- U32TO8_LITTLE(c + 12, x3);
- U32TO8_LITTLE(c + 16, x4);
- U32TO8_LITTLE(c + 20, x5);
- U32TO8_LITTLE(c + 24, x6);
- U32TO8_LITTLE(c + 28, x7);
- U32TO8_LITTLE(c + 32, x8);
- U32TO8_LITTLE(c + 36, x9);
- U32TO8_LITTLE(c + 40, x10);
- U32TO8_LITTLE(c + 44, x11);
- U32TO8_LITTLE(c + 48, x12);
- U32TO8_LITTLE(c + 52, x13);
- U32TO8_LITTLE(c + 56, x14);
- U32TO8_LITTLE(c + 60, x15);
-
- if (bytes <= 64) {
- if (bytes < 64) {
- for (i = 0;i < bytes;++i) ctarget[i] = c[i];
- }
- chacha->input[12] = j12;
- chacha->input[13] = j13;
- return;
- }
- bytes -= 64;
- c += 64;
- }
}
diff --git a/lib/random/sysrandom.h b/lib/random/sysrandom.h
index d276be45..8acec5b7 100644
--- a/lib/random/sysrandom.h
+++ b/lib/random/sysrandom.h
@@ -11,5 +11,5 @@ static ssize_t getrandom(void *buf, size_t buflen, unsigned int flags) {
// Use getrandom()
#include <sys/random.h>
#else
- #error "Unsupported platform for secure random number generation"
+#error "Unsupported platform for secure random number generation"
#endif
diff --git a/lib/time/time_defs.h b/lib/time/time_defs.h
index 2ae1d9e4..214c26b9 100644
--- a/lib/time/time_defs.h
+++ b/lib/time/time_defs.h
@@ -7,25 +7,26 @@ typedef struct timeval Time;
static OptionalText_t _local_timezone = NONE_TEXT;
-static INLINE Text_t num_format(long n, const char *unit)
-{
- if (n == 0)
- return Text("now");
- return Text$from_str(String((int64_t)labs(n), " ", unit, (n == -1 || n == 1) ? "" : "s", n <= 0 ? " ago" : " later"));
+static INLINE Text_t num_format(long n, const char *unit) {
+ if (n == 0) return Text("now");
+ return Text$from_str(
+ String((int64_t)labs(n), " ", unit, (n == -1 || n == 1) ? "" : "s", n <= 0 ? " ago" : " later"));
}
-static void set_local_timezone(Text_t tz)
-{
+static void set_local_timezone(Text_t tz) {
setenv("TZ", Text$as_c_string(tz), 1);
_local_timezone = tz;
tzset();
}
-#define WITH_TIMEZONE(tz, body) ({ if (tz.length >= 0) { \
- OptionalText_t old_timezone = _local_timezone; \
- set_local_timezone(tz); \
- body; \
- set_local_timezone(old_timezone); \
- } else { \
- body; \
- }})
+#define WITH_TIMEZONE(tz, body) \
+ ({ \
+ if (tz.length >= 0) { \
+ OptionalText_t old_timezone = _local_timezone; \
+ set_local_timezone(tz); \
+ body; \
+ set_local_timezone(old_timezone); \
+ } else { \
+ body; \
+ } \
+ })
diff --git a/src/ast.c b/src/ast.c
index a1bcac58..7367580c 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -7,43 +7,66 @@
#include "stdlib/tables.h"
#include "stdlib/text.h"
-static Text_t quoted_text(const char *text) {
- return Text$quoted(Text$from_str(text), false, Text("\""));
-}
+static Text_t quoted_text(const char *text) { return Text$quoted(Text$from_str(text), false, Text("\"")); }
CONSTFUNC const char *binop_method_name(ast_e tag) {
switch (tag) {
- case Power: case PowerUpdate: return "power";
- case Multiply: case MultiplyUpdate: return "times";
- case Divide: case DivideUpdate: return "divided_by";
- case Mod: case ModUpdate: return "modulo";
- case Mod1: case Mod1Update: return "modulo1";
- case Plus: case PlusUpdate: return "plus";
- case Minus: case MinusUpdate: return "minus";
- case Concat: case ConcatUpdate: return "concatenated_with";
- case LeftShift: case LeftShiftUpdate: return "left_shifted";
- case RightShift: case RightShiftUpdate: return "right_shifted";
- case UnsignedLeftShift: case UnsignedLeftShiftUpdate: return "unsigned_left_shifted";
- case UnsignedRightShift: case UnsignedRightShiftUpdate: return "unsigned_right_shifted";
- case And: case AndUpdate: return "bit_and";
- case Or: case OrUpdate: return "bit_or";
- case Xor: case XorUpdate: return "bit_xor";
+ case Power:
+ case PowerUpdate: return "power";
+ case Multiply:
+ case MultiplyUpdate: return "times";
+ case Divide:
+ case DivideUpdate: return "divided_by";
+ case Mod:
+ case ModUpdate: return "modulo";
+ case Mod1:
+ case Mod1Update: return "modulo1";
+ case Plus:
+ case PlusUpdate: return "plus";
+ case Minus:
+ case MinusUpdate: return "minus";
+ case Concat:
+ case ConcatUpdate: return "concatenated_with";
+ case LeftShift:
+ case LeftShiftUpdate: return "left_shifted";
+ case RightShift:
+ case RightShiftUpdate: return "right_shifted";
+ case UnsignedLeftShift:
+ case UnsignedLeftShiftUpdate: return "unsigned_left_shifted";
+ case UnsignedRightShift:
+ case UnsignedRightShiftUpdate: return "unsigned_right_shifted";
+ case And:
+ case AndUpdate: return "bit_and";
+ case Or:
+ case OrUpdate: return "bit_or";
+ case Xor:
+ case XorUpdate: return "bit_xor";
default: return NULL;
}
};
CONSTFUNC const char *binop_operator(ast_e tag) {
switch (tag) {
- case Multiply: case MultiplyUpdate: return "*";
- case Divide: case DivideUpdate: return "/";
- case Mod: case ModUpdate: return "%";
- case Plus: case PlusUpdate: return "+";
- case Minus: case MinusUpdate: return "-";
- case LeftShift: case LeftShiftUpdate: return "<<";
- case RightShift: case RightShiftUpdate: return ">>";
- case And: case AndUpdate: return "&";
- case Or: case OrUpdate: return "|";
- case Xor: case XorUpdate: return "^";
+ case Multiply:
+ case MultiplyUpdate: return "*";
+ case Divide:
+ case DivideUpdate: return "/";
+ case Mod:
+ case ModUpdate: return "%";
+ case Plus:
+ case PlusUpdate: return "+";
+ case Minus:
+ case MinusUpdate: return "-";
+ case LeftShift:
+ case LeftShiftUpdate: return "<<";
+ case RightShift:
+ case RightShiftUpdate: return ">>";
+ case And:
+ case AndUpdate: return "&";
+ case Or:
+ case OrUpdate: return "|";
+ case Xor:
+ case XorUpdate: return "^";
case Equals: return "==";
case NotEquals: return "!=";
case LessThan: return "<";
@@ -62,8 +85,7 @@ static Text_t tags_to_sexp(tag_ast_t *tags);
static Text_t optional_sexp(const char *tag, ast_t *ast);
static Text_t optional_type_sexp(const char *tag, type_ast_t *ast);
-Text_t ast_list_to_sexp(ast_list_t *asts)
-{
+Text_t ast_list_to_sexp(ast_list_t *asts) {
Text_t c = EMPTY_TEXT;
for (; asts; asts = asts->next) {
c = Texts(c, " ", ast_to_sexp(asts->ast));
@@ -74,8 +96,8 @@ Text_t ast_list_to_sexp(ast_list_t *asts)
Text_t arg_defs_to_sexp(arg_ast_t *args) {
Text_t c = Text("(args");
for (arg_ast_t *arg = args; arg; arg = arg->next) {
- c = Texts(c, " (arg ", arg->name ? quoted_text(arg->name) : Text("nil"),
- " ", type_ast_to_sexp(arg->type), " ", ast_to_sexp(arg->value), ")");
+ c = Texts(c, " (arg ", arg->name ? quoted_text(arg->name) : Text("nil"), " ", type_ast_to_sexp(arg->type), " ",
+ ast_to_sexp(arg->value), ")");
}
return Texts(c, ")");
}
@@ -84,8 +106,7 @@ Text_t arg_list_to_sexp(arg_ast_t *args) {
Text_t c = EMPTY_TEXT;
for (arg_ast_t *arg = args; arg; arg = arg->next) {
assert(arg->value && !arg->type);
- if (arg->name)
- c = Texts(c, " :", arg->name);
+ if (arg->name) c = Texts(c, " :", arg->name);
c = Texts(c, " ", ast_to_sexp(arg->value));
}
return c;
@@ -107,118 +128,163 @@ Text_t tags_to_sexp(tag_ast_t *tags) {
return c;
}
-Text_t type_ast_to_sexp(type_ast_t *t)
-{
+Text_t type_ast_to_sexp(type_ast_t *t) {
if (!t) return Text("nil");
switch (t->tag) {
-#define T(type, ...) case type: { __typeof(t->__data.type) data = t->__data.type; (void)data; return Texts(__VA_ARGS__); }
- T(UnknownTypeAST, "(UnknownType)")
- T(VarTypeAST, "(VarType \"", data.name, "\")")
- T(PointerTypeAST, "(PointerType \"", data.is_stack ? "stack" : "heap", "\" ", type_ast_to_sexp(data.pointed), ")")
- T(ListTypeAST, "(ListType ", type_ast_to_sexp(data.item), ")")
- T(SetTypeAST, "(SetType ", type_ast_to_sexp(data.item), ")")
- T(TableTypeAST, "(TableType ", type_ast_to_sexp(data.key), " ", type_ast_to_sexp(data.value), ")")
- T(FunctionTypeAST, "(FunctionType ", arg_defs_to_sexp(data.args), " ", type_ast_to_sexp(data.ret), ")")
- T(OptionalTypeAST, "(OptionalType ", type_ast_to_sexp(data.type), ")")
+#define T(type, ...) \
+ case type: { \
+ __typeof(t->__data.type) data = t->__data.type; \
+ (void)data; \
+ return Texts(__VA_ARGS__); \
+ }
+ T(UnknownTypeAST, "(UnknownType)");
+ T(VarTypeAST, "(VarType \"", data.name, "\")");
+ T(PointerTypeAST, "(PointerType \"", data.is_stack ? "stack" : "heap", "\" ", type_ast_to_sexp(data.pointed),
+ ")");
+ T(ListTypeAST, "(ListType ", type_ast_to_sexp(data.item), ")");
+ T(SetTypeAST, "(SetType ", type_ast_to_sexp(data.item), ")");
+ T(TableTypeAST, "(TableType ", type_ast_to_sexp(data.key), " ", type_ast_to_sexp(data.value), ")");
+ T(FunctionTypeAST, "(FunctionType ", arg_defs_to_sexp(data.args), " ", type_ast_to_sexp(data.ret), ")");
+ T(OptionalTypeAST, "(OptionalType ", type_ast_to_sexp(data.type), ")");
#undef T
default: return EMPTY_TEXT;
}
}
-Text_t optional_sexp(const char *name, ast_t *ast)
-{
+Text_t optional_sexp(const char *name, ast_t *ast) {
return ast ? Texts(" :", name, " ", ast_to_sexp(ast)) : EMPTY_TEXT;
}
-Text_t optional_type_sexp(const char *name, type_ast_t *ast)
-{
+Text_t optional_type_sexp(const char *name, type_ast_t *ast) {
return ast ? Texts(" :", name, " ", type_ast_to_sexp(ast)) : EMPTY_TEXT;
}
-Text_t ast_to_sexp(ast_t *ast)
-{
+Text_t ast_to_sexp(ast_t *ast) {
if (!ast) return Text("nil");
switch (ast->tag) {
-#define T(type, ...) case type: { __typeof(ast->__data.type) data = ast->__data.type; (void)data; return Texts(__VA_ARGS__); }
- T(Unknown, "(Unknown)")
- T(None, "(None)")
- T(Bool, "(Bool ", data.b ? "yes" : "no", ")")
- T(Var, "(Var ", quoted_text(data.name), ")")
- T(Int, "(Int ", quoted_text(ast_source(ast)), ")")
- T(Num, "(Num ", quoted_text(ast_source(ast)), ")")
- T(TextLiteral, Text$quoted(data.text, false, Text("\"")))
- T(TextJoin, "(Text", data.lang ? Texts(" :lang ", quoted_text(data.lang)) : EMPTY_TEXT, ast_list_to_sexp(data.children), ")")
- T(Path, "(Path ", quoted_text(data.path), ")")
- T(Declare, "(Declare ", ast_to_sexp(data.var), " ", type_ast_to_sexp(data.type), " ", ast_to_sexp(data.value), ")")
- T(Assign, "(Assign (targets ", ast_list_to_sexp(data.targets), ") (values ", ast_list_to_sexp(data.values), "))")
+#define T(type, ...) \
+ case type: { \
+ __typeof(ast->__data.type) data = ast->__data.type; \
+ (void)data; \
+ return Texts(__VA_ARGS__); \
+ }
+ T(Unknown, "(Unknown)");
+ T(None, "(None)");
+ T(Bool, "(Bool ", data.b ? "yes" : "no", ")");
+ T(Var, "(Var ", quoted_text(data.name), ")");
+ T(Int, "(Int ", quoted_text(ast_source(ast)), ")");
+ T(Num, "(Num ", quoted_text(ast_source(ast)), ")");
+ T(TextLiteral, Text$quoted(data.text, false, Text("\"")));
+ T(TextJoin, "(Text", data.lang ? Texts(" :lang ", quoted_text(data.lang)) : EMPTY_TEXT,
+ ast_list_to_sexp(data.children), ")");
+ T(Path, "(Path ", quoted_text(data.path), ")");
+ T(Declare, "(Declare ", ast_to_sexp(data.var), " ", type_ast_to_sexp(data.type), " ", ast_to_sexp(data.value),
+ ")");
+ T(Assign, "(Assign (targets ", ast_list_to_sexp(data.targets), ") (values ", ast_list_to_sexp(data.values),
+ "))");
#define BINOP(name) T(name, "(" #name " ", ast_to_sexp(data.lhs), " ", ast_to_sexp(data.rhs), ")")
- BINOP(Power) BINOP(PowerUpdate) BINOP(Multiply) BINOP(MultiplyUpdate) BINOP(Divide) BINOP(DivideUpdate) BINOP(Mod) BINOP(ModUpdate)
- BINOP(Mod1) BINOP(Mod1Update) BINOP(Plus) BINOP(PlusUpdate) BINOP(Minus) BINOP(MinusUpdate) BINOP(Concat) BINOP(ConcatUpdate)
- BINOP(LeftShift) BINOP(LeftShiftUpdate) BINOP(RightShift) BINOP(RightShiftUpdate) BINOP(UnsignedLeftShift) BINOP(UnsignedLeftShiftUpdate)
- BINOP(UnsignedRightShift) BINOP(UnsignedRightShiftUpdate) BINOP(And) BINOP(AndUpdate) BINOP(Or) BINOP(OrUpdate)
- BINOP(Xor) BINOP(XorUpdate) BINOP(Compare)
- BINOP(Equals) BINOP(NotEquals) BINOP(LessThan) BINOP(LessThanOrEquals) BINOP(GreaterThan) BINOP(GreaterThanOrEquals)
+ BINOP(Power);
+ BINOP(PowerUpdate);
+ BINOP(Multiply);
+ BINOP(MultiplyUpdate);
+ BINOP(Divide);
+ BINOP(DivideUpdate);
+ BINOP(Mod);
+ BINOP(ModUpdate);
+ BINOP(Mod1);
+ BINOP(Mod1Update);
+ BINOP(Plus);
+ BINOP(PlusUpdate);
+ BINOP(Minus);
+ BINOP(MinusUpdate);
+ BINOP(Concat);
+ BINOP(ConcatUpdate);
+ BINOP(LeftShift);
+ BINOP(LeftShiftUpdate);
+ BINOP(RightShift);
+ BINOP(RightShiftUpdate);
+ BINOP(UnsignedLeftShift);
+ BINOP(UnsignedLeftShiftUpdate);
+ BINOP(UnsignedRightShift);
+ BINOP(UnsignedRightShiftUpdate);
+ BINOP(And);
+ BINOP(AndUpdate);
+ BINOP(Or);
+ BINOP(OrUpdate);
+ BINOP(Xor);
+ BINOP(XorUpdate);
+ BINOP(Compare);
+ BINOP(Equals);
+ BINOP(NotEquals);
+ BINOP(LessThan);
+ BINOP(LessThanOrEquals);
+ BINOP(GreaterThan);
+ BINOP(GreaterThanOrEquals);
#undef BINOP
- T(Negative, "(Negative ", ast_to_sexp(data.value), ")")
- T(Not, "(Not ", ast_to_sexp(data.value), ")")
- T(HeapAllocate, "(HeapAllocate ", ast_to_sexp(data.value), ")")
- T(StackReference, "(StackReference ", ast_to_sexp(data.value), ")")
- T(Min, "(Min ", ast_to_sexp(data.lhs), " ", ast_to_sexp(data.rhs), optional_sexp("key", data.key), ")")
- T(Max, "(Max ", ast_to_sexp(data.lhs), " ", ast_to_sexp(data.rhs), optional_sexp("key", data.key), ")")
- T(List, "(List", ast_list_to_sexp(data.items), ")")
- T(Set, "(Set", ast_list_to_sexp(data.items), ")")
- T(Table, "(Table", optional_sexp("default", data.default_value), optional_sexp("fallback", data.fallback),
- ast_list_to_sexp(data.entries), ")")
- T(TableEntry, "(TableEntry ", ast_to_sexp(data.key), " ", ast_to_sexp(data.value), ")")
- T(Comprehension, "(Comprehension ", ast_to_sexp(data.expr), " (vars", ast_list_to_sexp(data.vars), ") ",
- ast_to_sexp(data.iter), " ", optional_sexp("filter", data.filter), ")")
- T(FunctionDef, "(FunctionDef ", ast_to_sexp(data.name), " ", arg_defs_to_sexp(data.args),
- optional_type_sexp("return", data.ret_type), " ", ast_to_sexp(data.body), ")")
- T(ConvertDef, "(ConvertDef ", arg_defs_to_sexp(data.args), " ", type_ast_to_sexp(data.ret_type), " ", ast_to_sexp(data.body), ")")
- T(Lambda, "(Lambda ", arg_defs_to_sexp(data.args), optional_type_sexp("return", data.ret_type), " ", ast_to_sexp(data.body), ")")
- T(FunctionCall, "(FunctionCall ", ast_to_sexp(data.fn), arg_list_to_sexp(data.args), ")")
- T(MethodCall, "(MethodCall ", ast_to_sexp(data.self), " ", quoted_text(data.name), arg_list_to_sexp(data.args), ")")
- T(Block, "(Block", ast_list_to_sexp(data.statements), ")")
- T(For, "(For (vars", ast_list_to_sexp(data.vars), ") ", ast_to_sexp(data.iter), " ", ast_to_sexp(data.body),
- " ", ast_to_sexp(data.empty), ")")
- T(While, "(While ", ast_to_sexp(data.condition), " ", ast_to_sexp(data.body), ")")
- T(Repeat, "(Repeat ", ast_to_sexp(data.body), ")")
- T(If, "(If ", ast_to_sexp(data.condition), " ", ast_to_sexp(data.body), optional_sexp("else", data.else_body), ")")
- T(When, "(When ", ast_to_sexp(data.subject), when_clauses_to_sexp(data.clauses), optional_sexp("else", data.else_body), ")")
- T(Reduction, "(Reduction ", quoted_text(binop_method_name(data.op)), " ", ast_to_sexp(data.key), " ", ast_to_sexp(data.iter), ")")
- T(Skip, "(Skip ", quoted_text(data.target), ")")
- T(Stop, "(Stop ", quoted_text(data.target), ")")
- T(Pass, "(Pass)")
- T(Defer, "(Defer ", ast_to_sexp(data.body), ")")
- T(Return, "(Return ", ast_to_sexp(data.value), ")")
- T(Extern, "(Extern \"", data.name, "\" ", type_ast_to_sexp(data.type), ")")
- T(StructDef, "(StructDef \"", data.name, "\" ", arg_defs_to_sexp(data.fields), " ", ast_to_sexp(data.namespace), ")")
- T(EnumDef, "(EnumDef \"", data.name, "\" (tags ", tags_to_sexp(data.tags), ") ", ast_to_sexp(data.namespace), ")")
- T(LangDef, "(LangDef \"", data.name, "\" ", ast_to_sexp(data.namespace), ")")
- T(Index, "(Index ", ast_to_sexp(data.indexed), " ", ast_to_sexp(data.index), ")")
- T(FieldAccess, "(FieldAccess ", ast_to_sexp(data.fielded), " \"", data.field, "\")")
- T(Optional, "(Optional ", ast_to_sexp(data.value), ")")
- T(NonOptional, "(NonOptional ", ast_to_sexp(data.value), ")")
- T(DocTest, "(DocTest ", ast_to_sexp(data.expr), optional_sexp("expected", data.expected), ")")
- T(Assert, "(Assert ", ast_to_sexp(data.expr), " ", optional_sexp("message", data.message), ")")
- T(Use, "(Use ", optional_sexp("var", data.var), " ", quoted_text(data.path), ")")
- T(InlineCCode, "(InlineCCode ", ast_list_to_sexp(data.chunks), optional_type_sexp("type", data.type_ast), ")")
- T(Deserialize, "(Deserialize ", type_ast_to_sexp(data.type), " ", ast_to_sexp(data.value), ")")
- T(Extend, "(Extend \"", data.name, "\" ", ast_to_sexp(data.body), ")")
- default: errx(1, "S-expressions are not implemented for this AST");
+ T(Negative, "(Negative ", ast_to_sexp(data.value), ")");
+ T(Not, "(Not ", ast_to_sexp(data.value), ")");
+ T(HeapAllocate, "(HeapAllocate ", ast_to_sexp(data.value), ")");
+ T(StackReference, "(StackReference ", ast_to_sexp(data.value), ")");
+ T(Min, "(Min ", ast_to_sexp(data.lhs), " ", ast_to_sexp(data.rhs), optional_sexp("key", data.key), ")");
+ T(Max, "(Max ", ast_to_sexp(data.lhs), " ", ast_to_sexp(data.rhs), optional_sexp("key", data.key), ")");
+ T(List, "(List", ast_list_to_sexp(data.items), ")");
+ T(Set, "(Set", ast_list_to_sexp(data.items), ")");
+ T(Table, "(Table", optional_sexp("default", data.default_value), optional_sexp("fallback", data.fallback),
+ ast_list_to_sexp(data.entries), ")");
+ T(TableEntry, "(TableEntry ", ast_to_sexp(data.key), " ", ast_to_sexp(data.value), ")");
+ T(Comprehension, "(Comprehension ", ast_to_sexp(data.expr), " (vars", ast_list_to_sexp(data.vars), ") ",
+ ast_to_sexp(data.iter), " ", optional_sexp("filter", data.filter), ")");
+ T(FunctionDef, "(FunctionDef ", ast_to_sexp(data.name), " ", arg_defs_to_sexp(data.args),
+ optional_type_sexp("return", data.ret_type), " ", ast_to_sexp(data.body), ")");
+ T(ConvertDef, "(ConvertDef ", arg_defs_to_sexp(data.args), " ", type_ast_to_sexp(data.ret_type), " ",
+ ast_to_sexp(data.body), ")");
+ T(Lambda, "(Lambda ", arg_defs_to_sexp(data.args), optional_type_sexp("return", data.ret_type), " ",
+ ast_to_sexp(data.body), ")");
+ T(FunctionCall, "(FunctionCall ", ast_to_sexp(data.fn), arg_list_to_sexp(data.args), ")");
+ T(MethodCall, "(MethodCall ", ast_to_sexp(data.self), " ", quoted_text(data.name), arg_list_to_sexp(data.args),
+ ")")
+ T(Block, "(Block", ast_list_to_sexp(data.statements), ")");
+ T(For, "(For (vars", ast_list_to_sexp(data.vars), ") ", ast_to_sexp(data.iter), " ", ast_to_sexp(data.body),
+ " ", ast_to_sexp(data.empty), ")");
+ T(While, "(While ", ast_to_sexp(data.condition), " ", ast_to_sexp(data.body), ")");
+ T(Repeat, "(Repeat ", ast_to_sexp(data.body), ")");
+ T(If, "(If ", ast_to_sexp(data.condition), " ", ast_to_sexp(data.body), optional_sexp("else", data.else_body),
+ ")");
+ T(When, "(When ", ast_to_sexp(data.subject), when_clauses_to_sexp(data.clauses),
+ optional_sexp("else", data.else_body), ")");
+ T(Reduction, "(Reduction ", quoted_text(binop_method_name(data.op)), " ", ast_to_sexp(data.key), " ",
+ ast_to_sexp(data.iter), ")");
+ T(Skip, "(Skip ", quoted_text(data.target), ")");
+ T(Stop, "(Stop ", quoted_text(data.target), ")");
+ T(Pass, "(Pass)");
+ T(Defer, "(Defer ", ast_to_sexp(data.body), ")");
+ T(Return, "(Return ", ast_to_sexp(data.value), ")");
+ T(Extern, "(Extern \"", data.name, "\" ", type_ast_to_sexp(data.type), ")");
+ T(StructDef, "(StructDef \"", data.name, "\" ", arg_defs_to_sexp(data.fields), " ", ast_to_sexp(data.namespace),
+ ")");
+ T(EnumDef, "(EnumDef \"", data.name, "\" (tags ", tags_to_sexp(data.tags), ") ", ast_to_sexp(data.namespace),
+ ")");
+ T(LangDef, "(LangDef \"", data.name, "\" ", ast_to_sexp(data.namespace), ")");
+ T(Index, "(Index ", ast_to_sexp(data.indexed), " ", ast_to_sexp(data.index), ")");
+ T(FieldAccess, "(FieldAccess ", ast_to_sexp(data.fielded), " \"", data.field, "\")");
+ T(Optional, "(Optional ", ast_to_sexp(data.value), ")");
+ T(NonOptional, "(NonOptional ", ast_to_sexp(data.value), ")");
+ T(DocTest, "(DocTest ", ast_to_sexp(data.expr), optional_sexp("expected", data.expected), ")");
+ T(Assert, "(Assert ", ast_to_sexp(data.expr), " ", optional_sexp("message", data.message), ")");
+ T(Use, "(Use ", optional_sexp("var", data.var), " ", quoted_text(data.path), ")");
+ T(InlineCCode, "(InlineCCode ", ast_list_to_sexp(data.chunks), optional_type_sexp("type", data.type_ast), ")");
+ T(Deserialize, "(Deserialize ", type_ast_to_sexp(data.type), " ", ast_to_sexp(data.value), ")");
+ T(Extend, "(Extend \"", data.name, "\" ", ast_to_sexp(data.body), ")");
+ default: errx(1, "S-expressions are not implemented for this AST");
#undef T
}
}
-const char *ast_to_sexp_str(ast_t *ast)
-{
- return Text$as_c_string(ast_to_sexp(ast));
-}
+const char *ast_to_sexp_str(ast_t *ast) { return Text$as_c_string(ast_to_sexp(ast)); }
-const char *ast_source(ast_t *ast)
-{
+const char *ast_source(ast_t *ast) {
if (!ast) return NULL;
size_t len = (size_t)(ast->end - ast->start);
char *source = GC_MALLOC_ATOMIC(len + 1);
@@ -227,10 +293,14 @@ const char *ast_source(ast_t *ast)
return source;
}
-PUREFUNC bool is_idempotent(ast_t *ast)
-{
+PUREFUNC bool is_idempotent(ast_t *ast) {
switch (ast->tag) {
- case Int: case Bool: case Num: case Var: case None: case TextLiteral: return true;
+ case Int:
+ case Bool:
+ case Num:
+ case Var:
+ case None:
+ case TextLiteral: return true;
case Index: {
DeclareMatch(index, ast, Index);
return is_idempotent(index->indexed) && index->index != NULL && is_idempotent(index->index);
@@ -243,15 +313,13 @@ PUREFUNC bool is_idempotent(ast_t *ast)
}
}
-void _visit_topologically(ast_t *ast, Table_t definitions, Table_t *visited, Closure_t fn)
-{
- void (*visit)(void*, ast_t*) = (void*)fn.fn;
+void _visit_topologically(ast_t *ast, Table_t definitions, Table_t *visited, Closure_t fn) {
+ void (*visit)(void *, ast_t *) = (void *)fn.fn;
if (ast->tag == StructDef) {
DeclareMatch(def, ast, StructDef);
- if (Table$str_get(*visited, def->name))
- return;
+ if (Table$str_get(*visited, def->name)) return;
- Table$str_set(visited, def->name, (void*)_visit_topologically);
+ Table$str_set(visited, def->name, (void *)_visit_topologically);
for (arg_ast_t *field = def->fields; field; field = field->next) {
if (field->type && field->type->tag == VarTypeAST) {
const char *field_type_name = Match(field->type, VarTypeAST)->name;
@@ -260,15 +328,13 @@ void _visit_topologically(ast_t *ast, Table_t definitions, Table_t *visited, Clo
_visit_topologically(dependency, definitions, visited, fn);
}
}
-
}
visit(fn.userdata, ast);
} else if (ast->tag == EnumDef) {
DeclareMatch(def, ast, EnumDef);
- if (Table$str_get(*visited, def->name))
- return;
+ if (Table$str_get(*visited, def->name)) return;
- Table$str_set(visited, def->name, (void*)_visit_topologically);
+ Table$str_set(visited, def->name, (void *)_visit_topologically);
for (tag_ast_t *tag = def->tags; tag; tag = tag->next) {
for (arg_ast_t *field = tag->fields; field; field = field->next) {
if (field->type && field->type->tag == VarTypeAST) {
@@ -283,16 +349,14 @@ void _visit_topologically(ast_t *ast, Table_t definitions, Table_t *visited, Clo
visit(fn.userdata, ast);
} else if (ast->tag == LangDef) {
DeclareMatch(def, ast, LangDef);
- if (Table$str_get(*visited, def->name))
- return;
+ if (Table$str_get(*visited, def->name)) return;
visit(fn.userdata, ast);
} else {
visit(fn.userdata, ast);
}
}
-void visit_topologically(ast_list_t *asts, Closure_t fn)
-{
+void visit_topologically(ast_list_t *asts, Closure_t fn) {
// Visit each top-level statement in topological order:
// - 'use' statements first
// - then typedefs
@@ -313,12 +377,11 @@ void visit_topologically(ast_list_t *asts, Closure_t fn)
}
}
- void (*visit)(void*, ast_t*) = (void*)fn.fn;
+ void (*visit)(void *, ast_t *) = (void *)fn.fn;
Table_t visited = {};
// First: 'use' statements in order:
for (ast_list_t *stmt = asts; stmt; stmt = stmt->next) {
- if (stmt->ast->tag == Use)
- visit(fn.userdata, stmt->ast);
+ if (stmt->ast->tag == Use) visit(fn.userdata, stmt->ast);
}
// Then typedefs in topological order:
for (ast_list_t *stmt = asts; stmt; stmt = stmt->next) {
@@ -334,27 +397,35 @@ void visit_topologically(ast_list_t *asts, Closure_t fn)
}
}
-CONSTFUNC bool is_binary_operation(ast_t *ast)
-{
+CONSTFUNC bool is_binary_operation(ast_t *ast) {
switch (ast->tag) {
case BINOP_CASES: return true;
default: return false;
}
}
-CONSTFUNC bool is_update_assignment(ast_t *ast)
-{
+CONSTFUNC bool is_update_assignment(ast_t *ast) {
switch (ast->tag) {
- case PowerUpdate: case MultiplyUpdate: case DivideUpdate: case ModUpdate: case Mod1Update:
- case PlusUpdate: case MinusUpdate: case ConcatUpdate: case LeftShiftUpdate: case UnsignedLeftShiftUpdate:
- case RightShiftUpdate: case UnsignedRightShiftUpdate: case AndUpdate: case OrUpdate: case XorUpdate:
- return true;
+ case PowerUpdate:
+ case MultiplyUpdate:
+ case DivideUpdate:
+ case ModUpdate:
+ case Mod1Update:
+ case PlusUpdate:
+ case MinusUpdate:
+ case ConcatUpdate:
+ case LeftShiftUpdate:
+ case UnsignedLeftShiftUpdate:
+ case RightShiftUpdate:
+ case UnsignedRightShiftUpdate:
+ case AndUpdate:
+ case OrUpdate:
+ case XorUpdate: return true;
default: return false;
}
}
-CONSTFUNC ast_e binop_tag(ast_e tag)
-{
+CONSTFUNC ast_e binop_tag(ast_e tag) {
switch (tag) {
case PowerUpdate: return Power;
case MultiplyUpdate: return Multiply;
diff --git a/src/ast.h b/src/ast.h
index bda91fdd..814dfbd9 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -11,31 +11,46 @@
#include "stdlib/files.h"
#include "stdlib/util.h"
-#define NewAST(_file, _start, _end, ast_tag, ...) (new(ast_t, .file=_file, .start=_start, .end=_end,\
- .tag=ast_tag, .__data.ast_tag={__VA_ARGS__}))
-#define NewTypeAST(_file, _start, _end, ast_tag, ...) (new(type_ast_t, .file=_file, .start=_start, .end=_end,\
- .tag=ast_tag, .__data.ast_tag={__VA_ARGS__}))
-#define FakeAST(ast_tag, ...) (new(ast_t, .tag=ast_tag, .__data.ast_tag={__VA_ARGS__}))
-#define WrapAST(ast, ast_tag, ...) (new(ast_t, .file=(ast)->file, .start=(ast)->start, .end=(ast)->end, .tag=ast_tag, .__data.ast_tag={__VA_ARGS__}))
-#define TextAST(ast, _str) WrapAST(ast, TextLiteral, .str=GC_strdup(_str))
-#define LiteralCode(code, ...) new(ast_t, .tag=InlineCCode, .__data.InlineCCode={.chunks=new(ast_list_t, .ast=FakeAST(TextLiteral, code)), __VA_ARGS__})
-#define Match(x, _tag) ((x)->tag == _tag ? &(x)->__data._tag : (errx(1, __FILE__ ":%d This was supposed to be a " # _tag "\n", __LINE__), &(x)->__data._tag))
+#define NewAST(_file, _start, _end, ast_tag, ...) \
+ (new (ast_t, .file = _file, .start = _start, .end = _end, .tag = ast_tag, .__data.ast_tag = {__VA_ARGS__}))
+#define NewTypeAST(_file, _start, _end, ast_tag, ...) \
+ (new (type_ast_t, .file = _file, .start = _start, .end = _end, .tag = ast_tag, .__data.ast_tag = {__VA_ARGS__}))
+#define FakeAST(ast_tag, ...) (new (ast_t, .tag = ast_tag, .__data.ast_tag = {__VA_ARGS__}))
+#define WrapAST(ast, ast_tag, ...) \
+ (new (ast_t, .file = (ast)->file, .start = (ast)->start, .end = (ast)->end, .tag = ast_tag, \
+ .__data.ast_tag = {__VA_ARGS__}))
+#define TextAST(ast, _str) WrapAST(ast, TextLiteral, .str = GC_strdup(_str))
+#define LiteralCode(code, ...) \
+ new (ast_t, .tag = InlineCCode, \
+ .__data.InlineCCode = {.chunks = new (ast_list_t, .ast = FakeAST(TextLiteral, code)), __VA_ARGS__})
+#define Match(x, _tag) \
+ ((x)->tag == _tag ? &(x)->__data._tag \
+ : (errx(1, __FILE__ ":%d This was supposed to be a " #_tag "\n", __LINE__), &(x)->__data._tag))
#define DeclareMatch(var, x, _tag) __typeof((x)->__data._tag) *var = Match(x, _tag)
-#define BINARY_OPERANDS(ast) ({ if (!is_binary_operation(ast)) errx(1, __FILE__ ":%d This is not a binary operation!", __LINE__); (ast)->__data.Plus; })
-#define UPDATE_OPERANDS(ast) ({ if (!is_update_assignment(ast)) errx(1, __FILE__ ":%d This is not an update assignment!", __LINE__); (ast)->__data.PlusUpdate; })
+#define BINARY_OPERANDS(ast) \
+ ({ \
+ if (!is_binary_operation(ast)) errx(1, __FILE__ ":%d This is not a binary operation!", __LINE__); \
+ (ast)->__data.Plus; \
+ })
+#define UPDATE_OPERANDS(ast) \
+ ({ \
+ if (!is_update_assignment(ast)) errx(1, __FILE__ ":%d This is not an update assignment!", __LINE__); \
+ (ast)->__data.PlusUpdate; \
+ })
-#define REVERSE_LIST(list) do { \
- __typeof(list) _prev = NULL; \
- __typeof(list) _next = NULL; \
- __typeof(list) _current = list; \
- while (_current != NULL) { \
- _next = _current->next; \
- _current->next = _prev; \
- _prev = _current; \
- _current = _next; \
- } \
- list = _prev; \
-} while(0)
+#define REVERSE_LIST(list) \
+ do { \
+ __typeof(list) _prev = NULL; \
+ __typeof(list) _next = NULL; \
+ __typeof(list) _current = list; \
+ while (_current != NULL) { \
+ _next = _current->next; \
+ _current->next = _prev; \
+ _prev = _current; \
+ _current = _next; \
+ } \
+ list = _prev; \
+ } while (0)
struct binding_s;
typedef struct type_ast_s type_ast_t;
@@ -76,7 +91,7 @@ typedef struct tag_ast_s {
const char *name;
arg_ast_t *fields;
struct tag_ast_s *next;
- bool secret:1;
+ bool secret : 1;
} tag_ast_t;
struct type_ast_s {
@@ -84,13 +99,14 @@ struct type_ast_s {
file_t *file;
const char *start, *end;
union {
- struct {} UnknownTypeAST;
+ struct {
+ } UnknownTypeAST;
struct {
const char *name;
} VarTypeAST;
struct {
type_ast_t *pointed;
- bool is_stack:1;
+ bool is_stack : 1;
} PointerTypeAST;
struct {
type_ast_t *item;
@@ -112,42 +128,143 @@ struct type_ast_s {
} __data;
};
-#define BINOP_CASES Power: case Multiply: case Divide: case Mod: case Mod1: case Plus: case Minus: case Concat: case LeftShift: case UnsignedLeftShift: \
- case RightShift: case UnsignedRightShift: case Equals: case NotEquals: case LessThan: case LessThanOrEquals: case GreaterThan: \
- case GreaterThanOrEquals: case Compare: case And: case Or: case Xor: \
- case PowerUpdate: case MultiplyUpdate: case DivideUpdate: case ModUpdate: case Mod1Update: case PlusUpdate: case MinusUpdate: case ConcatUpdate: \
- case LeftShiftUpdate: case UnsignedLeftShiftUpdate
-#define UPDATE_CASES PowerUpdate: case MultiplyUpdate: case DivideUpdate: case ModUpdate: case Mod1Update: case PlusUpdate: case MinusUpdate: \
- case ConcatUpdate: case LeftShiftUpdate: case UnsignedLeftShiftUpdate: case RightShiftUpdate: case UnsignedRightShiftUpdate: \
- case AndUpdate: case OrUpdate: case XorUpdate
+#define BINOP_CASES \
+ Power: \
+ case Multiply: \
+ case Divide: \
+ case Mod: \
+ case Mod1: \
+ case Plus: \
+ case Minus: \
+ case Concat: \
+ case LeftShift: \
+ case UnsignedLeftShift: \
+ case RightShift: \
+ case UnsignedRightShift: \
+ case Equals: \
+ case NotEquals: \
+ case LessThan: \
+ case LessThanOrEquals: \
+ case GreaterThan: \
+ case GreaterThanOrEquals: \
+ case Compare: \
+ case And: \
+ case Or: \
+ case Xor: \
+ case PowerUpdate: \
+ case MultiplyUpdate: \
+ case DivideUpdate: \
+ case ModUpdate: \
+ case Mod1Update: \
+ case PlusUpdate: \
+ case MinusUpdate: \
+ case ConcatUpdate: \
+ case LeftShiftUpdate: \
+ case UnsignedLeftShiftUpdate
+#define UPDATE_CASES \
+ PowerUpdate: \
+ case MultiplyUpdate: \
+ case DivideUpdate: \
+ case ModUpdate: \
+ case Mod1Update: \
+ case PlusUpdate: \
+ case MinusUpdate: \
+ case ConcatUpdate: \
+ case LeftShiftUpdate: \
+ case UnsignedLeftShiftUpdate: \
+ case RightShiftUpdate: \
+ case UnsignedRightShiftUpdate: \
+ case AndUpdate: \
+ case OrUpdate: \
+ case XorUpdate
typedef enum {
Unknown = 0,
- None, Bool, Var,
- Int, Num,
- TextLiteral, TextJoin,
+ None,
+ Bool,
+ Var,
+ Int,
+ Num,
+ TextLiteral,
+ TextJoin,
Path,
- Declare, Assign,
- Power, Multiply, Divide, Mod, Mod1, Plus, Minus, Concat, LeftShift, UnsignedLeftShift,
- RightShift, UnsignedRightShift, Equals, NotEquals, LessThan, LessThanOrEquals, GreaterThan,
- GreaterThanOrEquals, Compare, And, Or, Xor,
- PowerUpdate, MultiplyUpdate, DivideUpdate, ModUpdate, Mod1Update, PlusUpdate, MinusUpdate, ConcatUpdate, LeftShiftUpdate, UnsignedLeftShiftUpdate,
- RightShiftUpdate, UnsignedRightShiftUpdate, AndUpdate, OrUpdate, XorUpdate,
- Not, Negative, HeapAllocate, StackReference,
- Min, Max,
- List, Set, Table, TableEntry, Comprehension,
- FunctionDef, Lambda, ConvertDef,
- FunctionCall, MethodCall,
+ Declare,
+ Assign,
+ Power,
+ Multiply,
+ Divide,
+ Mod,
+ Mod1,
+ Plus,
+ Minus,
+ Concat,
+ LeftShift,
+ UnsignedLeftShift,
+ RightShift,
+ UnsignedRightShift,
+ Equals,
+ NotEquals,
+ LessThan,
+ LessThanOrEquals,
+ GreaterThan,
+ GreaterThanOrEquals,
+ Compare,
+ And,
+ Or,
+ Xor,
+ PowerUpdate,
+ MultiplyUpdate,
+ DivideUpdate,
+ ModUpdate,
+ Mod1Update,
+ PlusUpdate,
+ MinusUpdate,
+ ConcatUpdate,
+ LeftShiftUpdate,
+ UnsignedLeftShiftUpdate,
+ RightShiftUpdate,
+ UnsignedRightShiftUpdate,
+ AndUpdate,
+ OrUpdate,
+ XorUpdate,
+ Not,
+ Negative,
+ HeapAllocate,
+ StackReference,
+ Min,
+ Max,
+ List,
+ Set,
+ Table,
+ TableEntry,
+ Comprehension,
+ FunctionDef,
+ Lambda,
+ ConvertDef,
+ FunctionCall,
+ MethodCall,
Block,
- For, While, If, When, Repeat,
+ For,
+ While,
+ If,
+ When,
+ Repeat,
Reduction,
- Skip, Stop, Pass,
+ Skip,
+ Stop,
+ Pass,
Defer,
Return,
Extern,
- StructDef, EnumDef, LangDef,
- Index, FieldAccess, Optional, NonOptional,
- DocTest, Assert,
+ StructDef,
+ EnumDef,
+ LangDef,
+ Index,
+ FieldAccess,
+ Optional,
+ NonOptional,
+ DocTest,
+ Assert,
Use,
InlineCCode,
Deserialize,
@@ -160,8 +277,10 @@ struct ast_s {
file_t *file;
const char *start, *end;
union {
- struct {} Unknown;
- struct {} None;
+ struct {
+ } Unknown;
+ struct {
+ } None;
struct {
bool b;
} Bool;
@@ -180,7 +299,7 @@ struct ast_s {
struct {
const char *lang;
ast_list_t *children;
- bool colorize:1;
+ bool colorize : 1;
} TextJoin;
struct {
const char *path;
@@ -189,16 +308,16 @@ struct ast_s {
ast_t *var;
type_ast_t *type;
ast_t *value;
- bool top_level:1;
+ bool top_level : 1;
} Declare;
struct {
ast_list_t *targets, *values;
} Assign;
binary_operands_t Power, Multiply, Divide, Mod, Mod1, Plus, Minus, Concat, LeftShift, UnsignedLeftShift,
- RightShift, UnsignedRightShift, Equals, NotEquals, LessThan, LessThanOrEquals, GreaterThan,
- GreaterThanOrEquals, Compare, And, Or, Xor,
- PowerUpdate, MultiplyUpdate, DivideUpdate, ModUpdate, Mod1Update, PlusUpdate, MinusUpdate, ConcatUpdate, LeftShiftUpdate, UnsignedLeftShiftUpdate,
- RightShiftUpdate, UnsignedRightShiftUpdate, AndUpdate, OrUpdate, XorUpdate;
+ RightShift, UnsignedRightShift, Equals, NotEquals, LessThan, LessThanOrEquals, GreaterThan,
+ GreaterThanOrEquals, Compare, And, Or, Xor, PowerUpdate, MultiplyUpdate, DivideUpdate, ModUpdate,
+ Mod1Update, PlusUpdate, MinusUpdate, ConcatUpdate, LeftShiftUpdate, UnsignedLeftShiftUpdate,
+ RightShiftUpdate, UnsignedRightShiftUpdate, AndUpdate, OrUpdate, XorUpdate;
struct {
ast_t *value;
} Not, Negative, HeapAllocate, StackReference;
@@ -281,7 +400,8 @@ struct ast_s {
struct {
const char *target;
} Skip, Stop;
- struct {} Pass;
+ struct {
+ } Pass;
struct {
ast_t *body;
} Defer;
@@ -296,7 +416,7 @@ struct ast_s {
const char *name;
arg_ast_t *fields;
ast_t *namespace;
- bool secret:1, external:1, opaque:1;
+ bool secret : 1, external : 1, opaque : 1;
} StructDef;
struct {
const char *name;
@@ -320,7 +440,7 @@ struct ast_s {
} Optional, NonOptional;
struct {
ast_t *expr, *expected;
- bool skip_source:1;
+ bool skip_source : 1;
} DocTest;
struct {
ast_t *expr, *message;
diff --git a/src/compile.c b/src/compile.c
index a747b870..438e6cce 100644
--- a/src/compile.c
+++ b/src/compile.c
@@ -1,14 +1,14 @@
// Compilation logic
#include <ctype.h>
-#include <glob.h>
#include <gc.h>
+#include <glob.h>
#include <gmp.h>
#include <stdio.h>
#include <uninorm.h>
#include "ast.h"
-#include "config.h"
#include "compile.h"
+#include "config.h"
#include "enums.h"
#include "environment.h"
#include "modules.h"
@@ -22,7 +22,7 @@
#include "structs.h"
#include "typecheck.h"
-typedef ast_t* (*comprehension_body_t)(ast_t*, ast_t*);
+typedef ast_t *(*comprehension_body_t)(ast_t *, ast_t *);
static Text_t compile_to_pointer_depth(env_t *env, ast_t *ast, int64_t target_depth, bool needs_incref);
static Text_t compile_text(env_t *env, ast_t *ast, Text_t color);
@@ -47,16 +47,11 @@ static ast_t *add_to_table_comprehension(ast_t *entry, ast_t *subject);
static ast_t *add_to_set_comprehension(ast_t *item, ast_t *subject);
static Text_t compile_lvalue(env_t *env, ast_t *ast);
-static Text_t quoted_str(const char *str) {
- return Text$quoted(Text$from_str(str), false, Text("\""));
-}
+static Text_t quoted_str(const char *str) { return Text$quoted(Text$from_str(str), false, Text("\"")); }
-static inline Text_t quoted_text(Text_t text) {
- return Text$quoted(text, false, Text("\""));
-}
+static inline Text_t quoted_text(Text_t text) { return Text$quoted(text, false, Text("\"")); }
-Text_t promote_to_optional(type_t *t, Text_t code)
-{
+Text_t promote_to_optional(type_t *t, Text_t code) {
if (t == PATH_TYPE || t == PATH_TYPE_TYPE) {
return code;
} else if (t->tag == IntType) {
@@ -71,27 +66,23 @@ Text_t promote_to_optional(type_t *t, Text_t code)
} else if (t->tag == ByteType) {
return Texts("((OptionalByte_t){.value=", code, "})");
} else if (t->tag == StructType) {
- return Texts("({ ", compile_type(Type(OptionalType, .type=t)), " nonnull = {.value=", code, "}; nonnull.is_none = false; nonnull; })");
+ return Texts("({ ", compile_type(Type(OptionalType, .type = t)), " nonnull = {.value=", code,
+ "}; nonnull.is_none = false; nonnull; })");
} else {
return code;
}
}
-static Text_t with_source_info(env_t *env, ast_t *ast, Text_t code)
-{
- if (code.length == 0 || !ast || !ast->file || !env->do_source_mapping)
- return code;
+static Text_t with_source_info(env_t *env, ast_t *ast, Text_t code) {
+ if (code.length == 0 || !ast || !ast->file || !env->do_source_mapping) return code;
int64_t line = get_line_number(ast->file, ast->start);
return Texts("\n#line ", String(line), "\n", code);
}
-static bool promote(env_t *env, ast_t *ast, Text_t *code, type_t *actual, type_t *needed)
-{
- if (type_eq(actual, needed))
- return true;
+static bool promote(env_t *env, ast_t *ast, Text_t *code, type_t *actual, type_t *needed) {
+ if (type_eq(actual, needed)) return true;
- if (!can_promote(actual, needed))
- return false;
+ if (!can_promote(actual, needed)) return false;
if (needed->tag == ClosureType && actual->tag == FunctionType) {
*code = Texts("((Closure_t){", *code, ", NULL})");
@@ -100,8 +91,7 @@ static bool promote(env_t *env, ast_t *ast, Text_t *code, type_t *actual, type_t
// Empty promotion:
type_t *more_complete = most_complete_type(actual, needed);
- if (more_complete)
- return true;
+ if (more_complete) return true;
// Optional promotion:
if (needed->tag == OptionalType && type_eq(actual, Match(needed, OptionalType)->type)) {
@@ -116,28 +106,25 @@ static bool promote(env_t *env, ast_t *ast, Text_t *code, type_t *actual, type_t
}
// Lang to Text_t:
- if (actual->tag == TextType && needed->tag == TextType && streq(Match(needed, TextType)->lang, "Text"))
- return true;
+ if (actual->tag == TextType && needed->tag == TextType && streq(Match(needed, TextType)->lang, "Text")) return true;
// Automatic optional checking for nums:
if (needed->tag == NumType && actual->tag == OptionalType && Match(actual, OptionalType)->type->tag == NumType) {
int64_t line = get_line_number(ast->file, ast->start);
- *code = Texts("({ ", compile_declaration(actual, Text("opt")), " = ", *code, "; ",
- "if unlikely (", check_none(actual, Text("opt")), ")\n",
- "#line ", String(line), "\n",
- "fail_source(", quoted_str(ast->file->filename), ", ",
- String((int64_t)(ast->start - ast->file->text)), ", ",
- String((int64_t)(ast->end - ast->file->text)), ", ",
- "\"This was expected to be a value, but it's none\");\n",
- optional_into_nonnone(actual, Text("opt")), "; })");
+ *code = Texts("({ ", compile_declaration(actual, Text("opt")), " = ", *code, "; ", "if unlikely (",
+ check_none(actual, Text("opt")), ")\n", "#line ", String(line), "\n", "fail_source(",
+ quoted_str(ast->file->filename), ", ", String((int64_t)(ast->start - ast->file->text)), ", ",
+ String((int64_t)(ast->end - ast->file->text)), ", ",
+ "\"This was expected to be a value, but it's none\");\n",
+ optional_into_nonnone(actual, Text("opt")), "; })");
return true;
}
// Numeric promotions/demotions
if ((is_numeric_type(actual) || actual->tag == BoolType) && (is_numeric_type(needed) || needed->tag == BoolType)) {
- arg_ast_t *args = new(arg_ast_t, .value=LiteralCode(*code, .type=actual));
- binding_t *constructor = get_constructor(env, needed, args,
- env->current_type != NULL && type_eq(env->current_type, value_type(needed)));
+ arg_ast_t *args = new (arg_ast_t, .value = LiteralCode(*code, .type = actual));
+ binding_t *constructor = get_constructor(
+ env, needed, args, env->current_type != NULL && type_eq(env->current_type, value_type(needed)));
if (constructor) {
DeclareMatch(fn, constructor->type, FunctionType);
if (fn->args->next == NULL) {
@@ -152,8 +139,7 @@ static bool promote(env_t *env, ast_t *ast, Text_t *code, type_t *actual, type_t
binding_t *b = get_binding(Match(needed, EnumType)->env, tag);
assert(b && b->type->tag == FunctionType);
// Single-value enum constructor:
- if (!promote(env, ast, code, actual, Match(b->type, FunctionType)->args->type))
- return false;
+ if (!promote(env, ast, code, actual, Match(b->type, FunctionType)->args->type)) return false;
*code = Texts(b->code, "(", *code, ")");
return true;
}
@@ -165,22 +151,18 @@ static bool promote(env_t *env, ast_t *ast, Text_t *code, type_t *actual, type_t
}
// Automatic dereferencing:
- if (actual->tag == PointerType
- && can_promote(Match(actual, PointerType)->pointed, needed)) {
+ if (actual->tag == PointerType && can_promote(Match(actual, PointerType)->pointed, needed)) {
*code = Texts("*(", *code, ")");
return promote(env, ast, code, Match(actual, PointerType)->pointed, needed);
}
// Stack ref promotion:
- if (actual->tag == PointerType && needed->tag == PointerType)
- return true;
+ if (actual->tag == PointerType && needed->tag == PointerType) return true;
// Cross-promotion between tables with default values and without
- if (needed->tag == TableType && actual->tag == TableType)
- return true;
+ if (needed->tag == TableType && actual->tag == TableType) return true;
- if (needed->tag == ClosureType && actual->tag == ClosureType)
- return true;
+ if (needed->tag == ClosureType && actual->tag == ClosureType) return true;
if (needed->tag == FunctionType && actual->tag == FunctionType) {
*code = Texts("(", compile_type(needed), ")", *code);
@@ -197,29 +179,24 @@ static bool promote(env_t *env, ast_t *ast, Text_t *code, type_t *actual, type_t
return false;
}
-Text_t compile_maybe_incref(env_t *env, ast_t *ast, type_t *t)
-{
+Text_t compile_maybe_incref(env_t *env, ast_t *ast, type_t *t) {
if (is_idempotent(ast) && can_be_mutated(env, ast)) {
- if (t->tag == ListType)
- return Texts("LIST_COPY(", compile_to_type(env, ast, t), ")");
+ if (t->tag == ListType) return Texts("LIST_COPY(", compile_to_type(env, ast, t), ")");
else if (t->tag == TableType || t->tag == SetType)
return Texts("TABLE_COPY(", compile_to_type(env, ast, t), ")");
}
return compile_to_type(env, ast, t);
}
-static void add_closed_vars(Table_t *closed_vars, env_t *enclosing_scope, env_t *env, ast_t *ast)
-{
- if (ast == NULL)
- return;
+static void add_closed_vars(Table_t *closed_vars, env_t *enclosing_scope, env_t *env, ast_t *ast) {
+ if (ast == NULL) return;
switch (ast->tag) {
case Var: {
binding_t *b = get_binding(enclosing_scope, Match(ast, Var)->name);
if (b) {
binding_t *shadow = get_binding(env, Match(ast, Var)->name);
- if (!shadow || shadow == b)
- Table$str_set(closed_vars, Match(ast, Var)->name, b);
+ if (!shadow || shadow == b) Table$str_set(closed_vars, Match(ast, Var)->name, b);
}
break;
}
@@ -247,7 +224,10 @@ static void add_closed_vars(Table_t *closed_vars, env_t *enclosing_scope, env_t
add_closed_vars(closed_vars, enclosing_scope, env, binop.rhs);
break;
}
- case Not: case Negative: case HeapAllocate: case StackReference: {
+ case Not:
+ case Negative:
+ case HeapAllocate:
+ case StackReference: {
// UNSAFE:
ast_t *value = ast->__data.Not.value;
// END UNSAFE
@@ -291,16 +271,15 @@ static void add_closed_vars(Table_t *closed_vars, env_t *enclosing_scope, env_t
case Comprehension: {
DeclareMatch(comp, ast, Comprehension);
if (comp->expr->tag == Comprehension) { // Nested comprehension
- ast_t *body = comp->filter ? WrapAST(ast, If, .condition=comp->filter, .body=comp->expr) : comp->expr;
- ast_t *loop = WrapAST(ast, For, .vars=comp->vars, .iter=comp->iter, .body=body);
+ ast_t *body = comp->filter ? WrapAST(ast, If, .condition = comp->filter, .body = comp->expr) : comp->expr;
+ ast_t *loop = WrapAST(ast, For, .vars = comp->vars, .iter = comp->iter, .body = body);
return add_closed_vars(closed_vars, enclosing_scope, env, loop);
}
// List/Set/Table comprehension:
ast_t *body = comp->expr;
- if (comp->filter)
- body = WrapAST(comp->expr, If, .condition=comp->filter, .body=body);
- ast_t *loop = WrapAST(ast, For, .vars=comp->vars, .iter=comp->iter, .body=body);
+ if (comp->filter) body = WrapAST(comp->expr, If, .condition = comp->filter, .body = body);
+ ast_t *loop = WrapAST(ast, For, .vars = comp->vars, .iter = comp->iter, .body = body);
add_closed_vars(closed_vars, enclosing_scope, env, loop);
break;
}
@@ -356,8 +335,7 @@ static void add_closed_vars(Table_t *closed_vars, env_t *enclosing_scope, env_t
ast_t *var = Match(condition, Declare)->var;
type_t *cond_t = get_type(truthy_scope, var);
if (cond_t->tag == OptionalType) {
- set_binding(truthy_scope, Match(var, Var)->name,
- Match(cond_t, OptionalType)->type, EMPTY_TEXT);
+ set_binding(truthy_scope, Match(var, Var)->name, Match(cond_t, OptionalType)->type, EMPTY_TEXT);
}
add_closed_vars(closed_vars, enclosing_scope, truthy_scope, if_->body);
add_closed_vars(closed_vars, enclosing_scope, env, if_->else_body);
@@ -367,8 +345,7 @@ static void add_closed_vars(Table_t *closed_vars, env_t *enclosing_scope, env_t
type_t *cond_t = get_type(env, condition);
if (condition->tag == Var && cond_t->tag == OptionalType) {
truthy_scope = fresh_scope(env);
- set_binding(truthy_scope, Match(condition, Var)->name,
- Match(cond_t, OptionalType)->type, EMPTY_TEXT);
+ set_binding(truthy_scope, Match(condition, Var)->name, Match(cond_t, OptionalType)->type, EMPTY_TEXT);
}
add_closed_vars(closed_vars, enclosing_scope, truthy_scope, if_->body);
add_closed_vars(closed_vars, enclosing_scope, env, if_->else_body);
@@ -386,20 +363,17 @@ static void add_closed_vars(Table_t *closed_vars, env_t *enclosing_scope, env_t
add_closed_vars(closed_vars, enclosing_scope, env, clause->body);
}
- if (when->else_body)
- add_closed_vars(closed_vars, enclosing_scope, env, when->else_body);
+ if (when->else_body) add_closed_vars(closed_vars, enclosing_scope, env, when->else_body);
return;
}
DeclareMatch(enum_t, subject_t, EnumType);
for (when_clause_t *clause = when->clauses; clause; clause = clause->next) {
const char *clause_tag_name;
- if (clause->pattern->tag == Var)
- clause_tag_name = Match(clause->pattern, Var)->name;
+ if (clause->pattern->tag == Var) clause_tag_name = Match(clause->pattern, Var)->name;
else if (clause->pattern->tag == FunctionCall && Match(clause->pattern, FunctionCall)->fn->tag == Var)
clause_tag_name = Match(Match(clause->pattern, FunctionCall)->fn, Var)->name;
- else
- code_err(clause->pattern, "This is not a valid pattern for a ", type_to_str(subject_t), " enum");
+ else code_err(clause->pattern, "This is not a valid pattern for a ", type_to_str(subject_t), " enum");
type_t *tag_type = NULL;
for (tag_t *tag = enum_t->tags; tag; tag = tag->next) {
@@ -412,8 +386,7 @@ static void add_closed_vars(Table_t *closed_vars, env_t *enclosing_scope, env_t
env_t *scope = when_clause_scope(env, subject_t, clause);
add_closed_vars(closed_vars, enclosing_scope, scope, clause->body);
}
- if (when->else_body)
- add_closed_vars(closed_vars, enclosing_scope, env, when->else_body);
+ if (when->else_body) add_closed_vars(closed_vars, enclosing_scope, env, when->else_body);
break;
}
case Repeat: {
@@ -424,7 +397,8 @@ static void add_closed_vars(Table_t *closed_vars, env_t *enclosing_scope, env_t
DeclareMatch(reduction, ast, Reduction);
static int64_t next_id = 1;
ast_t *item = FakeAST(Var, String("$it", next_id++));
- ast_t *loop = FakeAST(For, .vars=new(ast_list_t, .ast=item), .iter=reduction->iter, .body=FakeAST(Pass));
+ ast_t *loop =
+ FakeAST(For, .vars = new (ast_list_t, .ast = item), .iter = reduction->iter, .body = FakeAST(Pass));
env_t *scope = for_scope(env, loop);
add_closed_vars(closed_vars, enclosing_scope, scope, reduction->key ? reduction->key : item);
break;
@@ -472,16 +446,20 @@ static void add_closed_vars(Table_t *closed_vars, env_t *enclosing_scope, env_t
add_closed_vars(closed_vars, enclosing_scope, env, Match(ast, ExplicitlyTyped)->ast);
break;
}
- case Use: case FunctionDef: case ConvertDef: case StructDef: case EnumDef: case LangDef: case Extend: {
+ case Use:
+ case FunctionDef:
+ case ConvertDef:
+ case StructDef:
+ case EnumDef:
+ case LangDef:
+ case Extend: {
errx(1, "Definitions should not be reachable in a closure.");
}
- default:
- break;
+ default: break;
}
}
-static Table_t get_closed_vars(env_t *env, arg_ast_t *args, ast_t *block)
-{
+static Table_t get_closed_vars(env_t *env, arg_ast_t *args, ast_t *block) {
env_t *body_scope = fresh_scope(env);
for (arg_ast_t *arg = args; arg; arg = arg->next) {
type_t *arg_type = get_arg_ast_type(env, arg);
@@ -493,8 +471,7 @@ static Table_t get_closed_vars(env_t *env, arg_ast_t *args, ast_t *block)
return closed_vars;
}
-Text_t compile_declaration(type_t *t, Text_t name)
-{
+Text_t compile_declaration(type_t *t, Text_t name) {
if (t->tag == FunctionType) {
DeclareMatch(fn, t, FunctionType);
Text_t code = Texts(compile_type(fn->ret), " (*", name, ")(");
@@ -511,10 +488,8 @@ Text_t compile_declaration(type_t *t, Text_t name)
}
}
-static Text_t compile_update_assignment(env_t *env, ast_t *ast)
-{
- if (!is_update_assignment(ast))
- code_err(ast, "This is not an update assignment");
+static Text_t compile_update_assignment(env_t *env, ast_t *ast) {
+ if (!is_update_assignment(ast)) code_err(ast, "This is not an update assignment");
binary_operands_t update = UPDATE_OPERANDS(ast);
@@ -557,35 +532,34 @@ static Text_t compile_update_assignment(env_t *env, ast_t *ast)
}
case AndUpdate: {
if (lhs_t->tag == BoolType)
- update_assignment = Texts("if (", lhs, ") ", lhs, " = ", compile_to_type(env, update.rhs, Type(BoolType)), ";");
+ update_assignment =
+ Texts("if (", lhs, ") ", lhs, " = ", compile_to_type(env, update.rhs, Type(BoolType)), ";");
break;
}
case OrUpdate: {
if (lhs_t->tag == BoolType)
- update_assignment = Texts("if (!", lhs, ") ", lhs, " = ", compile_to_type(env, update.rhs, Type(BoolType)), ";");
+ update_assignment =
+ Texts("if (!", lhs, ") ", lhs, " = ", compile_to_type(env, update.rhs, Type(BoolType)), ";");
break;
}
default: break;
}
if (update_assignment.length == 0) {
- ast_t *binop = new(ast_t);
+ ast_t *binop = new (ast_t);
*binop = *ast;
binop->tag = binop_tag(binop->tag);
- if (needs_idemotency_fix)
- binop->__data.Plus.lhs = LiteralCode(Text("*lhs"), .type=lhs_t);
+ if (needs_idemotency_fix) binop->__data.Plus.lhs = LiteralCode(Text("*lhs"), .type = lhs_t);
update_assignment = Texts(lhs, " = ", compile_to_type(env, binop, lhs_t), ";");
}
-
+
if (needs_idemotency_fix)
- return Texts("{ ", compile_declaration(Type(PointerType, .pointed=lhs_t), Text("lhs")), " = &", compile_lvalue(env, update.lhs), "; ",
- update_assignment, "; }");
- else
- return update_assignment;
+ return Texts("{ ", compile_declaration(Type(PointerType, .pointed = lhs_t), Text("lhs")), " = &",
+ compile_lvalue(env, update.lhs), "; ", update_assignment, "; }");
+ else return update_assignment;
}
-static Text_t compile_binary_op(env_t *env, ast_t *ast)
-{
+static Text_t compile_binary_op(env_t *env, ast_t *ast) {
binary_operands_t binop = BINARY_OPERANDS(ast);
type_t *lhs_t = get_type(env, binop.lhs);
type_t *rhs_t = get_type(env, binop.rhs);
@@ -594,7 +568,7 @@ static Text_t compile_binary_op(env_t *env, ast_t *ast)
binding_t *b = get_metamethod_binding(env, ast->tag, binop.lhs, binop.rhs, overall_t);
if (!b) b = get_metamethod_binding(env, ast->tag, binop.rhs, binop.lhs, overall_t);
if (b) {
- arg_ast_t *args = new(arg_ast_t, .value=binop.lhs, .next=new(arg_ast_t, .value=binop.rhs));
+ arg_ast_t *args = new (arg_ast_t, .value = binop.lhs, .next = new (arg_ast_t, .value = binop.rhs));
DeclareMatch(fn, b->type, FunctionType);
return Texts(b->code, "(", compile_arguments(env, ast, fn->args, args), ")");
}
@@ -604,7 +578,7 @@ static Text_t compile_binary_op(env_t *env, ast_t *ast)
if (b && b->type->tag == FunctionType) {
DeclareMatch(fn, b->type, FunctionType);
if (type_eq(fn->ret, rhs_t)) {
- arg_ast_t *args = new(arg_ast_t, .value=binop.rhs, .next=new(arg_ast_t, .value=binop.lhs));
+ arg_ast_t *args = new (arg_ast_t, .value = binop.rhs, .next = new (arg_ast_t, .value = binop.lhs));
if (is_valid_call(env, fn->args, args, true))
return Texts(b->code, "(", compile_arguments(env, ast, fn->args, args), ")");
}
@@ -614,7 +588,7 @@ static Text_t compile_binary_op(env_t *env, ast_t *ast)
if (b && b->type->tag == FunctionType) {
DeclareMatch(fn, b->type, FunctionType);
if (type_eq(fn->ret, lhs_t)) {
- arg_ast_t *args = new(arg_ast_t, .value=binop.lhs, .next=new(arg_ast_t, .value=binop.rhs));
+ arg_ast_t *args = new (arg_ast_t, .value = binop.lhs, .next = new (arg_ast_t, .value = binop.rhs));
if (is_valid_call(env, fn->args, args, true))
return Texts(b->code, "(", compile_arguments(env, ast, fn->args, args), ")");
}
@@ -624,7 +598,7 @@ static Text_t compile_binary_op(env_t *env, ast_t *ast)
if (b && b->type->tag == FunctionType) {
DeclareMatch(fn, b->type, FunctionType);
if (type_eq(fn->ret, lhs_t)) {
- arg_ast_t *args = new(arg_ast_t, .value=binop.lhs, .next=new(arg_ast_t, .value=binop.rhs));
+ arg_ast_t *args = new (arg_ast_t, .value = binop.lhs, .next = new (arg_ast_t, .value = binop.rhs));
if (is_valid_call(env, fn->args, args, true))
return Texts(b->code, "(", compile_arguments(env, ast, fn->args, args), ")");
}
@@ -634,7 +608,7 @@ static Text_t compile_binary_op(env_t *env, ast_t *ast)
if (b && b->type->tag == FunctionType) {
DeclareMatch(fn, b->type, FunctionType);
if (type_eq(fn->ret, lhs_t)) {
- arg_ast_t *args = new(arg_ast_t, .value=binop.lhs, .next=new(arg_ast_t, .value=binop.rhs));
+ arg_ast_t *args = new (arg_ast_t, .value = binop.lhs, .next = new (arg_ast_t, .value = binop.rhs));
if (is_valid_call(env, fn->args, args, true))
return Texts(b->code, "(", compile_arguments(env, ast, fn->args, args), ")");
}
@@ -643,29 +617,31 @@ static Text_t compile_binary_op(env_t *env, ast_t *ast)
if (ast->tag == Or && lhs_t->tag == OptionalType) {
if (rhs_t->tag == AbortType || rhs_t->tag == ReturnType) {
- return Texts("({ ", compile_declaration(lhs_t, Text("lhs")), " = ", compile(env, binop.lhs), "; ",
- "if (", check_none(lhs_t, Text("lhs")), ") ", compile_statement(env, binop.rhs), " ",
- optional_into_nonnone(lhs_t, Text("lhs")), "; })");
+ return Texts("({ ", compile_declaration(lhs_t, Text("lhs")), " = ", compile(env, binop.lhs), "; ", "if (",
+ check_none(lhs_t, Text("lhs")), ") ", compile_statement(env, binop.rhs), " ",
+ optional_into_nonnone(lhs_t, Text("lhs")), "; })");
}
if (is_incomplete_type(rhs_t)) {
type_t *complete = most_complete_type(rhs_t, Match(lhs_t, OptionalType)->type);
if (complete == NULL)
- code_err(binop.rhs, "I don't know how to convert a ", type_to_str(rhs_t), " to a ", type_to_str(Match(lhs_t, OptionalType)->type));
+ code_err(binop.rhs, "I don't know how to convert a ", type_to_str(rhs_t), " to a ",
+ type_to_str(Match(lhs_t, OptionalType)->type));
rhs_t = complete;
}
if (rhs_t->tag == OptionalType && type_eq(lhs_t, rhs_t)) {
return Texts("({ ", compile_declaration(lhs_t, Text("lhs")), " = ", compile(env, binop.lhs), "; ",
- check_none(lhs_t, Text("lhs")), " ? ", compile(env, binop.rhs), " : lhs; })");
+ check_none(lhs_t, Text("lhs")), " ? ", compile(env, binop.rhs), " : lhs; })");
} else if (rhs_t->tag != OptionalType && type_eq(Match(lhs_t, OptionalType)->type, rhs_t)) {
return Texts("({ ", compile_declaration(lhs_t, Text("lhs")), " = ", compile(env, binop.lhs), "; ",
- check_none(lhs_t, Text("lhs")), " ? ", compile(env, binop.rhs), " : ",
- optional_into_nonnone(lhs_t, Text("lhs")), "; })");
+ check_none(lhs_t, Text("lhs")), " ? ", compile(env, binop.rhs), " : ",
+ optional_into_nonnone(lhs_t, Text("lhs")), "; })");
} else if (rhs_t->tag == BoolType) {
return Texts("((!", check_none(lhs_t, compile(env, binop.lhs)), ") || ", compile(env, binop.rhs), ")");
} else {
- code_err(ast, "I don't know how to do an 'or' operation between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
+ code_err(ast, "I don't know how to do an 'or' operation between ", type_to_str(lhs_t), " and ",
+ type_to_str(rhs_t));
}
}
@@ -678,70 +654,98 @@ static Text_t compile_binary_op(env_t *env, ast_t *ast)
code_err(ast, "Exponentiation is only supported for Num types, not ", type_to_str(overall_t));
if (overall_t->tag == NumType && Match(overall_t, NumType)->bits == TYPE_NBITS32)
return Texts("powf(", lhs, ", ", rhs, ")");
- else
- return Texts("pow(", lhs, ", ", rhs, ")");
+ else return Texts("pow(", lhs, ", ", rhs, ")");
}
case Multiply: {
if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
- code_err(ast, "Math operations are only supported for values of the same numeric type, not ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
+ code_err(ast,
+ "Math operations are only supported for values of the same "
+ "numeric type, not ",
+ type_to_str(lhs_t), " and ", type_to_str(rhs_t));
return Texts("(", lhs, " * ", rhs, ")");
}
case Divide: {
if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
- code_err(ast, "Math operations are only supported for values of the same numeric type, not ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
+ code_err(ast,
+ "Math operations are only supported for values of the same "
+ "numeric type, not ",
+ type_to_str(lhs_t), " and ", type_to_str(rhs_t));
return Texts("(", lhs, " / ", rhs, ")");
}
case Mod: {
if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
- code_err(ast, "Math operations are only supported for values of the same numeric type, not ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
+ code_err(ast,
+ "Math operations are only supported for values of the same "
+ "numeric type, not ",
+ type_to_str(lhs_t), " and ", type_to_str(rhs_t));
return Texts("(", lhs, " % ", rhs, ")");
}
case Mod1: {
if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
- code_err(ast, "Math operations are only supported for values of the same numeric type, not ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
+ code_err(ast,
+ "Math operations are only supported for values of the same "
+ "numeric type, not ",
+ type_to_str(lhs_t), " and ", type_to_str(rhs_t));
return Texts("((((", lhs, ")-1) % (", rhs, ")) + 1)");
}
case Plus: {
if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
- code_err(ast, "Math operations are only supported for values of the same numeric type, not ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
+ code_err(ast,
+ "Math operations are only supported for values of the same "
+ "numeric type, not ",
+ type_to_str(lhs_t), " and ", type_to_str(rhs_t));
return Texts("(", lhs, " + ", rhs, ")");
}
case Minus: {
if (overall_t->tag == SetType)
return Texts("Table$without(", lhs, ", ", rhs, ", ", compile_type_info(overall_t), ")");
if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
- code_err(ast, "Math operations are only supported for values of the same numeric type, not ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
+ code_err(ast,
+ "Math operations are only supported for values of the same "
+ "numeric type, not ",
+ type_to_str(lhs_t), " and ", type_to_str(rhs_t));
return Texts("(", lhs, " - ", rhs, ")");
}
case LeftShift: {
if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
- code_err(ast, "Math operations are only supported for values of the same numeric type, not ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
+ code_err(ast,
+ "Math operations are only supported for values of the same "
+ "numeric type, not ",
+ type_to_str(lhs_t), " and ", type_to_str(rhs_t));
return Texts("(", lhs, " << ", rhs, ")");
}
case RightShift: {
if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
- code_err(ast, "Math operations are only supported for values of the same numeric type, not ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
+ code_err(ast,
+ "Math operations are only supported for values of the same "
+ "numeric type, not ",
+ type_to_str(lhs_t), " and ", type_to_str(rhs_t));
return Texts("(", lhs, " >> ", rhs, ")");
}
case UnsignedLeftShift: {
if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
- code_err(ast, "Math operations are only supported for values of the same numeric type, not ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
+ code_err(ast,
+ "Math operations are only supported for values of the same "
+ "numeric type, not ",
+ type_to_str(lhs_t), " and ", type_to_str(rhs_t));
return Texts("(", compile_type(overall_t), ")((", compile_unsigned_type(lhs_t), ")", lhs, " << ", rhs, ")");
}
case UnsignedRightShift: {
if (overall_t->tag != IntType && overall_t->tag != NumType && overall_t->tag != ByteType)
- code_err(ast, "Math operations are only supported for values of the same numeric type, not ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
+ code_err(ast,
+ "Math operations are only supported for values of the same "
+ "numeric type, not ",
+ type_to_str(lhs_t), " and ", type_to_str(rhs_t));
return Texts("(", compile_type(overall_t), ")((", compile_unsigned_type(lhs_t), ")", lhs, " >> ", rhs, ")");
}
case And: {
- if (overall_t->tag == BoolType)
- return Texts("(", lhs, " && ", rhs, ")");
- else if (overall_t->tag == IntType || overall_t->tag == ByteType)
- return Texts("(", lhs, " & ", rhs, ")");
+ if (overall_t->tag == BoolType) return Texts("(", lhs, " && ", rhs, ")");
+ else if (overall_t->tag == IntType || overall_t->tag == ByteType) return Texts("(", lhs, " & ", rhs, ")");
else if (overall_t->tag == SetType)
return Texts("Table$overlap(", lhs, ", ", rhs, ", ", compile_type_info(overall_t), ")");
else
- code_err(ast, "The 'and' operator isn't supported between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t), " values");
+ code_err(ast, "The 'and' operator isn't supported between ", type_to_str(lhs_t), " and ",
+ type_to_str(rhs_t), " values");
}
case Compare: {
return Texts("generic_compare(stack(", lhs, "), stack(", rhs, "), ", compile_type_info(overall_t), ")");
@@ -754,7 +758,8 @@ static Text_t compile_binary_op(env_t *env, ast_t *ast)
} else if (overall_t->tag == SetType) {
return Texts("Table$with(", lhs, ", ", rhs, ", ", compile_type_info(overall_t), ")");
} else {
- code_err(ast, "The 'or' operator isn't supported between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t), " values");
+ code_err(ast, "The 'or' operator isn't supported between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t),
+ " values");
}
}
case Xor: {
@@ -764,20 +769,22 @@ static Text_t compile_binary_op(env_t *env, ast_t *ast)
else if (overall_t->tag == SetType)
return Texts("Table$xor(", lhs, ", ", rhs, ", ", compile_type_info(overall_t), ")");
else
- code_err(ast, "The 'xor' operator isn't supported between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t), " values");
+ code_err(ast, "The 'xor' operator isn't supported between ", type_to_str(lhs_t), " and ",
+ type_to_str(rhs_t), " values");
}
case Concat: {
- if (overall_t == PATH_TYPE)
- return Texts("Path$concat(", lhs, ", ", rhs, ")");
+ if (overall_t == PATH_TYPE) return Texts("Path$concat(", lhs, ", ", rhs, ")");
switch (overall_t->tag) {
case TextType: {
return Texts("Text$concat(", lhs, ", ", rhs, ")");
}
case ListType: {
- return Texts("List$concat(", lhs, ", ", rhs, ", sizeof(", compile_type(Match(overall_t, ListType)->item_type), "))");
+ return Texts("List$concat(", lhs, ", ", rhs, ", sizeof(",
+ compile_type(Match(overall_t, ListType)->item_type), "))");
}
default:
- code_err(ast, "Concatenation isn't supported between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t), " values");
+ code_err(ast, "Concatenation isn't supported between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t),
+ " values");
}
}
default: errx(1, "Not a valid binary operation: %s", ast_to_sexp_str(ast));
@@ -785,10 +792,8 @@ static Text_t compile_binary_op(env_t *env, ast_t *ast)
return EMPTY_TEXT;
}
-PUREFUNC Text_t compile_unsigned_type(type_t *t)
-{
- if (t->tag != IntType)
- errx(1, "Not an int type, so unsigned doesn't make sense!");
+PUREFUNC Text_t compile_unsigned_type(type_t *t) {
+ if (t->tag != IntType) errx(1, "Not an int type, so unsigned doesn't make sense!");
switch (Match(t, IntType)->bits) {
case TYPE_IBITS8: return Text("uint8_t");
case TYPE_IBITS16: return Text("uint16_t");
@@ -799,8 +804,7 @@ PUREFUNC Text_t compile_unsigned_type(type_t *t)
return EMPTY_TEXT;
}
-Text_t compile_type(type_t *t)
-{
+Text_t compile_type(type_t *t) {
if (t == PATH_TYPE) return Text("Path_t");
else if (t == PATH_TYPE_TYPE) return Text("PathType_t");
@@ -814,13 +818,13 @@ Text_t compile_type(type_t *t)
case CStringType: return Text("const char*");
case BigIntType: return Text("Int_t");
case IntType: return Texts("Int", String(Match(t, IntType)->bits), "_t");
- case NumType: return Match(t, NumType)->bits == TYPE_NBITS64 ? Text("Num_t") : Texts("Num", String(Match(t, NumType)->bits), "_t");
+ case NumType:
+ return Match(t, NumType)->bits == TYPE_NBITS64 ? Text("Num_t")
+ : Texts("Num", String(Match(t, NumType)->bits), "_t");
case TextType: {
DeclareMatch(text, t, TextType);
- if (!text->lang || streq(text->lang, "Text"))
- return Text("Text_t");
- else
- return namespace_name(text->env, text->env->namespace, Text("$type"));
+ if (!text->lang || streq(text->lang, "Text")) return Text("Text_t");
+ else return namespace_name(text->env, text->env->namespace, Text("$type"));
}
case ListType: return Text("List_t");
case SetType: return Text("Table_t");
@@ -832,8 +836,7 @@ Text_t compile_type(type_t *t)
code = Texts(code, compile_type(arg->type));
if (arg->next) code = Texts(code, ", ");
}
- if (!fn->args)
- code = Texts(code, "void");
+ if (!fn->args) code = Texts(code, "void");
return Texts(code, ")");
}
case ClosureType: return Text("Closure_t");
@@ -850,24 +853,27 @@ Text_t compile_type(type_t *t)
case OptionalType: {
type_t *nonnull = Match(t, OptionalType)->type;
switch (nonnull->tag) {
- case CStringType: case FunctionType: case ClosureType:
- case PointerType: case EnumType:
- return compile_type(nonnull);
- case TextType:
- return Match(nonnull, TextType)->lang ? compile_type(nonnull) : Text("OptionalText_t");
- case IntType: case BigIntType: case NumType: case BoolType: case ByteType:
- case ListType: case TableType: case SetType:
- return Texts("Optional", compile_type(nonnull));
+ case CStringType:
+ case FunctionType:
+ case ClosureType:
+ case PointerType:
+ case EnumType: return compile_type(nonnull);
+ case TextType: return Match(nonnull, TextType)->lang ? compile_type(nonnull) : Text("OptionalText_t");
+ case IntType:
+ case BigIntType:
+ case NumType:
+ case BoolType:
+ case ByteType:
+ case ListType:
+ case TableType:
+ case SetType: return Texts("Optional", compile_type(nonnull));
case StructType: {
- if (nonnull == PATH_TYPE)
- return Text("OptionalPath_t");
- if (nonnull == PATH_TYPE_TYPE)
- return Text("OptionalPathType_t");
+ if (nonnull == PATH_TYPE) return Text("OptionalPath_t");
+ if (nonnull == PATH_TYPE_TYPE) return Text("OptionalPathType_t");
DeclareMatch(s, nonnull, StructType);
return namespace_name(s->env, s->env->namespace->parent, Texts("$Optional", s->name, "$$type"));
}
- default:
- compiler_err(NULL, NULL, NULL, "Optional types are not supported for: ", type_to_str(t));
+ default: compiler_err(NULL, NULL, NULL, "Optional types are not supported for: ", type_to_str(t));
}
}
case TypeInfoType: return Text("TypeInfo_t");
@@ -876,18 +882,19 @@ Text_t compile_type(type_t *t)
return EMPTY_TEXT;
}
-Text_t compile_lvalue(env_t *env, ast_t *ast)
-{
+Text_t compile_lvalue(env_t *env, ast_t *ast) {
if (!can_be_mutated(env, ast)) {
if (ast->tag == Index) {
ast_t *subject = Match(ast, Index)->indexed;
- code_err(subject, "This is an immutable value, you can't mutate its contents");
+ code_err(subject, "This is an immutable value, you can't mutate "
+ "its contents");
} else if (ast->tag == FieldAccess) {
ast_t *subject = Match(ast, FieldAccess)->fielded;
type_t *t = get_type(env, subject);
code_err(subject, "This is an immutable ", type_to_str(t), " value, you can't assign to its fields");
} else {
- code_err(ast, "This is a value of type ", type_to_str(get_type(env, ast)), " and can't be used as an assignment target");
+ code_err(ast, "This is a value of type ", type_to_str(get_type(env, ast)),
+ " and can't be used as an assignment target");
}
}
@@ -895,47 +902,44 @@ Text_t compile_lvalue(env_t *env, ast_t *ast)
DeclareMatch(index, ast, Index);
type_t *container_t = get_type(env, index->indexed);
if (container_t->tag == OptionalType)
- code_err(index->indexed, "This value might be none, so it can't be safely used as an assignment target");
+ code_err(index->indexed, "This value might be none, so it can't be "
+ "safely used as an assignment target");
- if (!index->index && container_t->tag == PointerType)
- return compile(env, ast);
+ if (!index->index && container_t->tag == PointerType) return compile(env, ast);
container_t = value_type(container_t);
type_t *index_t = get_type(env, index->index);
if (container_t->tag == ListType) {
Text_t target_code = compile_to_pointer_depth(env, index->indexed, 1, false);
type_t *item_type = Match(container_t, ListType)->item_type;
- Text_t index_code = index->index->tag == Int
- ? compile_int_to_type(env, index->index, Type(IntType, .bits=TYPE_IBITS64))
- : (index_t->tag == BigIntType ? Texts("Int64$from_int(", compile(env, index->index), ", no)")
- : Texts("(Int64_t)(", compile(env, index->index), ")"));
+ Text_t index_code =
+ index->index->tag == Int
+ ? compile_int_to_type(env, index->index, Type(IntType, .bits = TYPE_IBITS64))
+ : (index_t->tag == BigIntType ? Texts("Int64$from_int(", compile(env, index->index), ", no)")
+ : Texts("(Int64_t)(", compile(env, index->index), ")"));
if (index->unchecked) {
- return Texts("List_lvalue_unchecked(", compile_type(item_type), ", ", target_code, ", ",
- index_code, ")");
+ return Texts("List_lvalue_unchecked(", compile_type(item_type), ", ", target_code, ", ", index_code,
+ ")");
} else {
- return Texts("List_lvalue(", compile_type(item_type), ", ", target_code, ", ",
- index_code,
- ", ", String((int)(ast->start - ast->file->text)),
- ", ", String((int)(ast->end - ast->file->text)), ")");
+ return Texts("List_lvalue(", compile_type(item_type), ", ", target_code, ", ", index_code, ", ",
+ String((int)(ast->start - ast->file->text)), ", ",
+ String((int)(ast->end - ast->file->text)), ")");
}
} else if (container_t->tag == TableType) {
DeclareMatch(table_type, container_t, TableType);
if (table_type->default_value) {
type_t *value_type = get_type(env, table_type->default_value);
- return Texts("*Table$get_or_setdefault(",
- compile_to_pointer_depth(env, index->indexed, 1, false), ", ",
- compile_type(table_type->key_type), ", ",
- compile_type(value_type), ", ",
- compile_to_type(env, index->index, table_type->key_type), ", ",
- compile_to_type(env, table_type->default_value, table_type->value_type), ", ",
- compile_type_info(container_t), ")");
+ return Texts("*Table$get_or_setdefault(", compile_to_pointer_depth(env, index->indexed, 1, false), ", ",
+ compile_type(table_type->key_type), ", ", compile_type(value_type), ", ",
+ compile_to_type(env, index->index, table_type->key_type), ", ",
+ compile_to_type(env, table_type->default_value, table_type->value_type), ", ",
+ compile_type_info(container_t), ")");
}
- if (index->unchecked)
- code_err(ast, "Table indexes cannot be unchecked");
+ if (index->unchecked) code_err(ast, "Table indexes cannot be unchecked");
return Texts("*(", compile_type(Type(PointerType, table_type->value_type)), ")Table$reserve(",
- compile_to_pointer_depth(env, index->indexed, 1, false), ", ",
- compile_to_type(env, index->index, Type(PointerType, table_type->key_type, .is_stack=true)), ", NULL,",
- compile_type_info(container_t), ")");
+ compile_to_pointer_depth(env, index->indexed, 1, false), ", ",
+ compile_to_type(env, index->index, Type(PointerType, table_type->key_type, .is_stack = true)),
+ ", NULL,", compile_type_info(container_t), ")");
} else {
code_err(ast, "I don't know how to assign to this target");
}
@@ -947,15 +951,12 @@ Text_t compile_lvalue(env_t *env, ast_t *ast)
return EMPTY_TEXT;
}
-static Text_t compile_assignment(env_t *env, ast_t *target, Text_t value)
-{
+static Text_t compile_assignment(env_t *env, ast_t *target, Text_t value) {
return Texts(compile_lvalue(env, target), " = ", value);
}
-static Text_t compile_inline_block(env_t *env, ast_t *ast)
-{
- if (ast->tag != Block)
- return compile_statement(env, ast);
+static Text_t compile_inline_block(env_t *env, ast_t *ast) {
+ if (ast->tag != Block) return compile_statement(env, ast);
Text_t code = EMPTY_TEXT;
ast_list_t *stmts = Match(ast, Block)->statements;
@@ -973,60 +974,44 @@ static Text_t compile_inline_block(env_t *env, ast_t *ast)
return code;
}
-Text_t optional_into_nonnone(type_t *t, Text_t value)
-{
+Text_t optional_into_nonnone(type_t *t, Text_t value) {
if (t->tag == OptionalType) t = Match(t, OptionalType)->type;
switch (t->tag) {
- case IntType: case ByteType:
- return Texts(value, ".value");
+ case IntType:
+ case ByteType: return Texts(value, ".value");
case StructType:
- if (t == PATH_TYPE || t == PATH_TYPE_TYPE)
- return value;
+ if (t == PATH_TYPE || t == PATH_TYPE_TYPE) return value;
return Texts(value, ".value");
- default:
- return value;
+ default: return value;
}
}
-Text_t check_none(type_t *t, Text_t value)
-{
+Text_t check_none(type_t *t, Text_t value) {
t = Match(t, OptionalType)->type;
// NOTE: these use statement expressions ({...;}) because some compilers
// complain about excessive parens around equality comparisons
if (t->tag == PointerType || t->tag == FunctionType || t->tag == CStringType)
return Texts("({", value, " == NULL;})");
- else if (t == PATH_TYPE)
- return Texts("({(", value, ").type.$tag == PATH_NONE;})");
- else if (t == PATH_TYPE_TYPE)
- return Texts("({(", value, ").$tag == PATH_NONE;})");
- else if (t->tag == BigIntType)
- return Texts("({(", value, ").small == 0;})");
- else if (t->tag == ClosureType)
- return Texts("({(", value, ").fn == NULL;})");
+ else if (t == PATH_TYPE) return Texts("({(", value, ").type.$tag == PATH_NONE;})");
+ else if (t == PATH_TYPE_TYPE) return Texts("({(", value, ").$tag == PATH_NONE;})");
+ else if (t->tag == BigIntType) return Texts("({(", value, ").small == 0;})");
+ else if (t->tag == ClosureType) return Texts("({(", value, ").fn == NULL;})");
else if (t->tag == NumType)
return Texts(Match(t, NumType)->bits == TYPE_NBITS64 ? "Num$isnan(" : "Num32$isnan(", value, ")");
- else if (t->tag == ListType)
- return Texts("({(", value, ").length < 0;})");
- else if (t->tag == TableType || t->tag == SetType)
- return Texts("({(", value, ").entries.length < 0;})");
- else if (t->tag == BoolType)
- return Texts("({(", value, ") == NONE_BOOL;})");
- else if (t->tag == TextType)
- return Texts("({(", value, ").length < 0;})");
- else if (t->tag == IntType || t->tag == ByteType || t->tag == StructType)
- return Texts("(", value, ").is_none");
+ else if (t->tag == ListType) return Texts("({(", value, ").length < 0;})");
+ else if (t->tag == TableType || t->tag == SetType) return Texts("({(", value, ").entries.length < 0;})");
+ else if (t->tag == BoolType) return Texts("({(", value, ") == NONE_BOOL;})");
+ else if (t->tag == TextType) return Texts("({(", value, ").length < 0;})");
+ else if (t->tag == IntType || t->tag == ByteType || t->tag == StructType) return Texts("(", value, ").is_none");
else if (t->tag == EnumType) {
- if (enum_has_fields(t))
- return Texts("({(", value, ").$tag == 0;})");
- else
- return Texts("((", value, ") == 0)");
+ if (enum_has_fields(t)) return Texts("({(", value, ").$tag == 0;})");
+ else return Texts("((", value, ") == 0)");
}
print_err("Optional check not implemented for: ", type_to_str(t));
return EMPTY_TEXT;
}
-static Text_t compile_condition(env_t *env, ast_t *ast)
-{
+static Text_t compile_condition(env_t *env, ast_t *ast) {
type_t *t = get_type(env, ast);
if (t->tag == BoolType) {
return compile(env, ast);
@@ -1039,15 +1024,15 @@ static Text_t compile_condition(env_t *env, ast_t *ast)
} else if (t->tag == OptionalType) {
return Texts("!", check_none(t, compile(env, ast)));
} else if (t->tag == PointerType) {
- code_err(ast, "This pointer will always be non-none, so it should not be used in a conditional.");
+ code_err(ast, "This pointer will always be non-none, so it should not be "
+ "used in a conditional.");
} else {
code_err(ast, type_to_str(t), " values cannot be used for conditionals");
}
return EMPTY_TEXT;
}
-static Text_t _compile_statement(env_t *env, ast_t *ast)
-{
+static Text_t _compile_statement(env_t *env, ast_t *ast) {
switch (ast->tag) {
case When: {
// Typecheck to verify exhaustiveness:
@@ -1061,21 +1046,20 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
Text_t prefix = EMPTY_TEXT, suffix = EMPTY_TEXT;
ast_t *subject = when->subject;
if (!is_idempotent(when->subject)) {
- prefix = Texts("{\n", compile_declaration(subject_t, Text("_when_subject")), " = ", compile(env, subject), ";\n");
+ prefix = Texts("{\n", compile_declaration(subject_t, Text("_when_subject")), " = ",
+ compile(env, subject), ";\n");
suffix = Text("}\n");
- subject = LiteralCode(Text("_when_subject"), .type=subject_t);
+ subject = LiteralCode(Text("_when_subject"), .type = subject_t);
}
Text_t code = EMPTY_TEXT;
for (when_clause_t *clause = when->clauses; clause; clause = clause->next) {
- ast_t *comparison = WrapAST(clause->pattern, Equals, .lhs=subject, .rhs=clause->pattern);
+ ast_t *comparison = WrapAST(clause->pattern, Equals, .lhs = subject, .rhs = clause->pattern);
(void)get_type(env, comparison);
- if (code.length > 0)
- code = Texts(code, "else ");
+ if (code.length > 0) code = Texts(code, "else ");
code = Texts(code, "if (", compile(env, comparison), ")", compile_statement(env, clause->body));
}
- if (when->else_body)
- code = Texts(code, "else ", compile_statement(env, when->else_body));
+ if (when->else_body) code = Texts(code, "else ", compile_statement(env, when->else_body));
code = Texts(prefix, code, suffix);
return code;
}
@@ -1085,17 +1069,17 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
Text_t code;
if (enum_has_fields(subject_t))
code = Texts("WHEN(", compile_type(subject_t), ", ", compile(env, when->subject), ", _when_subject, {\n");
- else
- code = Texts("switch(", compile(env, when->subject), ") {\n");
+ else code = Texts("switch(", compile(env, when->subject), ") {\n");
for (when_clause_t *clause = when->clauses; clause; clause = clause->next) {
if (clause->pattern->tag == Var) {
const char *clause_tag_name = Match(clause->pattern, Var)->name;
type_t *clause_type = clause->body ? get_type(env, clause->body) : Type(VoidType);
- code = Texts(code, "case ", namespace_name(enum_t->env, enum_t->env->namespace, Texts("tag$", clause_tag_name)), ": {\n",
- compile_inline_block(env, clause->body),
- (clause_type->tag == ReturnType || clause_type->tag == AbortType) ? EMPTY_TEXT : Text("break;\n"),
- "}\n");
+ code = Texts(
+ code, "case ", namespace_name(enum_t->env, enum_t->env->namespace, Texts("tag$", clause_tag_name)),
+ ": {\n", compile_inline_block(env, clause->body),
+ (clause_type->tag == ReturnType || clause_type->tag == AbortType) ? EMPTY_TEXT : Text("break;\n"),
+ "}\n");
continue;
}
@@ -1103,7 +1087,8 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
code_err(clause->pattern, "This is not a valid pattern for a ", type_to_str(subject_t), " enum type");
const char *clause_tag_name = Match(Match(clause->pattern, FunctionCall)->fn, Var)->name;
- code = Texts(code, "case ", namespace_name(enum_t->env, enum_t->env->namespace, Texts("tag$", clause_tag_name)), ": {\n");
+ code = Texts(code, "case ",
+ namespace_name(enum_t->env, enum_t->env->namespace, Texts("tag$", clause_tag_name)), ": {\n");
type_t *tag_type = NULL;
for (tag_t *tag = enum_t->tags; tag; tag = tag->next) {
if (streq(tag->name, clause_tag_name)) {
@@ -1117,12 +1102,12 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
DeclareMatch(tag_struct, tag_type, StructType);
arg_ast_t *args = Match(clause->pattern, FunctionCall)->args;
if (args && !args->next && tag_struct->fields && tag_struct->fields->next) {
- if (args->value->tag != Var)
- code_err(args->value, "This is not a valid variable to bind to");
+ if (args->value->tag != Var) code_err(args->value, "This is not a valid variable to bind to");
const char *var_name = Match(args->value, Var)->name;
if (!streq(var_name, "_")) {
Text_t var = Texts("_$", var_name);
- code = Texts(code, compile_declaration(tag_type, var), " = _when_subject.", valid_c_name(clause_tag_name), ";\n");
+ code = Texts(code, compile_declaration(tag_type, var), " = _when_subject.",
+ valid_c_name(clause_tag_name), ";\n");
scope = fresh_scope(scope);
set_binding(scope, Match(args->value, Var)->name, tag_type, EMPTY_TEXT);
}
@@ -1131,11 +1116,10 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
arg_t *field = tag_struct->fields;
for (arg_ast_t *arg = args; arg || field; arg = arg->next) {
if (!arg)
- code_err(ast, "The field ", type_to_str(subject_t), ".", clause_tag_name, ".", field->name, " wasn't accounted for");
- if (!field)
- code_err(arg->value, "This is one more field than ", type_to_str(subject_t), " has");
- if (arg->name)
- code_err(arg->value, "Named arguments are not currently supported");
+ code_err(ast, "The field ", type_to_str(subject_t), ".", clause_tag_name, ".", field->name,
+ " wasn't accounted for");
+ if (!field) code_err(arg->value, "This is one more field than ", type_to_str(subject_t), " has");
+ if (arg->name) code_err(arg->value, "Named arguments are not currently supported");
const char *var_name = Match(arg->value, Var)->name;
if (!streq(var_name, "_")) {
@@ -1151,8 +1135,7 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
ast_list_t *statements = Match(clause->body, Block)->statements;
if (!statements || (statements->ast->tag == Pass && !statements->next))
code = Texts(code, "break;\n}\n");
- else
- code = Texts(code, compile_inline_block(scope, clause->body), "\nbreak;\n}\n");
+ else code = Texts(code, compile_inline_block(scope, clause->body), "\nbreak;\n}\n");
} else {
code = Texts(code, compile_statement(scope, clause->body), "\nbreak;\n}\n");
}
@@ -1162,8 +1145,7 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
ast_list_t *statements = Match(when->else_body, Block)->statements;
if (!statements || (statements->ast->tag == Pass && !statements->next))
code = Texts(code, "default: break;");
- else
- code = Texts(code, "default: {\n", compile_inline_block(env, when->else_body), "\nbreak;\n}\n");
+ else code = Texts(code, "default: {\n", compile_inline_block(env, when->else_body), "\nbreak;\n}\n");
} else {
code = Texts(code, "default: {\n", compile_statement(env, when->else_body), "\nbreak;\n}\n");
}
@@ -1176,8 +1158,7 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
case DocTest: {
DeclareMatch(test, ast, DocTest);
type_t *expr_t = get_type(env, test->expr);
- if (!expr_t)
- code_err(test->expr, "I couldn't figure out the type of this expression");
+ if (!expr_t) code_err(test->expr, "I couldn't figure out the type of this expression");
Text_t setup = EMPTY_TEXT;
Text_t test_code;
@@ -1199,28 +1180,37 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
&& value_type(get_type(env, Match(assign->targets->ast, Index)->indexed))->tag == TableType)
lhs_t = Match(lhs_t, OptionalType)->type;
if (has_stack_memory(lhs_t))
- code_err(test->expr, "Stack references cannot be assigned to variables because the variable's scope may outlive the scope of the stack memory.");
+ code_err(test->expr, "Stack references cannot be assigned "
+ "to variables because the "
+ "variable's scope may outlive the "
+ "scope of the stack memory.");
env_t *val_scope = with_enum_scope(env, lhs_t);
Text_t value = compile_to_type(val_scope, assign->values->ast, lhs_t);
test_code = Texts("(", compile_assignment(env, assign->targets->ast, value), ")");
expr_t = lhs_t;
} else {
- // Multi-assign or assignment to potentially non-idempotent targets
+ // Multi-assign or assignment to potentially non-idempotent
+ // targets
if (test->expected && assign->targets->next)
- code_err(ast, "Sorry, but doctesting with '=' is not supported for multi-assignments");
+ code_err(ast, "Sorry, but doctesting with '=' is not "
+ "supported for "
+ "multi-assignments");
test_code = Text("({ // Assignment\n");
int64_t i = 1;
- for (ast_list_t *target = assign->targets, *value = assign->values; target && value; target = target->next, value = value->next) {
+ for (ast_list_t *target = assign->targets, *value = assign->values; target && value;
+ target = target->next, value = value->next) {
type_t *lhs_t = get_type(env, target->ast);
if (target->ast->tag == Index && lhs_t->tag == OptionalType
&& value_type(get_type(env, Match(target->ast, Index)->indexed))->tag == TableType)
lhs_t = Match(lhs_t, OptionalType)->type;
if (has_stack_memory(lhs_t))
- code_err(ast, "Stack references cannot be assigned to variables because the variable's scope may outlive the scope of the stack memory.");
- if (target == assign->targets)
- expr_t = lhs_t;
+ code_err(ast, "Stack references cannot be assigned to "
+ "variables because the "
+ "variable's scope may outlive the scope "
+ "of the stack memory.");
+ if (target == assign->targets) expr_t = lhs_t;
env_t *val_scope = with_enum_scope(env, lhs_t);
Text_t val_code = compile_to_type(val_scope, value->ast, lhs_t);
test_code = Texts(test_code, compile_type(lhs_t), " $", String(i), " = ", val_code, ";\n");
@@ -1240,15 +1230,16 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
if (update.lhs->tag == Index) {
type_t *indexed = value_type(get_type(env, Match(update.lhs, Index)->indexed));
if (indexed->tag == TableType && Match(indexed, TableType)->default_value == NULL)
- code_err(update.lhs, "Update assignments are not currently supported for tables");
+ code_err(update.lhs, "Update assignments are not currently "
+ "supported for tables");
}
- ast_t *update_var = new(ast_t);
+ ast_t *update_var = new (ast_t);
*update_var = *test->expr;
- update_var->__data.PlusUpdate.lhs = LiteralCode(Text("(*expr)"), .type=lhs_t); // UNSAFE
- test_code = Texts("({",
- compile_declaration(Type(PointerType, lhs_t), Text("expr")), " = &(", compile_lvalue(env, update.lhs), "); ",
- compile_statement(env, update_var), "; *expr; })");
+ update_var->__data.PlusUpdate.lhs = LiteralCode(Text("(*expr)"), .type = lhs_t); // UNSAFE
+ test_code =
+ Texts("({", compile_declaration(Type(PointerType, lhs_t), Text("expr")), " = &(",
+ compile_lvalue(env, update.lhs), "); ", compile_statement(env, update_var), "; *expr; })");
expr_t = lhs_t;
} else if (expr_t->tag == VoidType || expr_t->tag == AbortType || expr_t->tag == ReturnType) {
test_code = Texts("({", compile_statement(env, test->expr), " NULL;})");
@@ -1256,27 +1247,19 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
test_code = compile(env, test->expr);
}
if (test->expected) {
- return Texts(
- setup,
- "test(", compile_type(expr_t), ", ", test_code, ", ",
- compile_to_type(env, test->expected, expr_t), ", ",
- compile_type_info(expr_t), ", ",
- String((int64_t)(test->expr->start - test->expr->file->text)), ", ",
- String((int64_t)(test->expr->end - test->expr->file->text)), ");");
+ return Texts(setup, "test(", compile_type(expr_t), ", ", test_code, ", ",
+ compile_to_type(env, test->expected, expr_t), ", ", compile_type_info(expr_t), ", ",
+ String((int64_t)(test->expr->start - test->expr->file->text)), ", ",
+ String((int64_t)(test->expr->end - test->expr->file->text)), ");");
} else {
if (expr_t->tag == VoidType || expr_t->tag == AbortType) {
- return Texts(
- setup,
- "inspect_void(", test_code, ", ", compile_type_info(expr_t), ", ",
- String((int64_t)(test->expr->start - test->expr->file->text)), ", ",
- String((int64_t)(test->expr->end - test->expr->file->text)), ");");
+ return Texts(setup, "inspect_void(", test_code, ", ", compile_type_info(expr_t), ", ",
+ String((int64_t)(test->expr->start - test->expr->file->text)), ", ",
+ String((int64_t)(test->expr->end - test->expr->file->text)), ");");
}
- return Texts(
- setup,
- "inspect(", compile_type(expr_t), ", ", test_code, ", ",
- compile_type_info(expr_t), ", ",
- String((int64_t)(test->expr->start - test->expr->file->text)), ", ",
- String((int64_t)(test->expr->end - test->expr->file->text)), ");");
+ return Texts(setup, "inspect(", compile_type(expr_t), ", ", test_code, ", ", compile_type_info(expr_t),
+ ", ", String((int64_t)(test->expr->start - test->expr->file->text)), ", ",
+ String((int64_t)(test->expr->end - test->expr->file->text)), ");");
}
}
case Assert: {
@@ -1286,67 +1269,69 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
switch (expr->tag) {
case And: {
DeclareMatch(and_, ast, And);
- return Texts(
- compile_statement(env, WrapAST(ast, Assert, .expr=and_->lhs, .message=message)),
- compile_statement(env, WrapAST(ast, Assert, .expr=and_->rhs, .message=message)));
+ return Texts(compile_statement(env, WrapAST(ast, Assert, .expr = and_->lhs, .message = message)),
+ compile_statement(env, WrapAST(ast, Assert, .expr = and_->rhs, .message = message)));
}
case Equals: failure = "!="; goto assert_comparison;
case NotEquals: failure = "=="; goto assert_comparison;
case LessThan: failure = ">="; goto assert_comparison;
case LessThanOrEquals: failure = ">"; goto assert_comparison;
case GreaterThan: failure = "<="; goto assert_comparison;
- case GreaterThanOrEquals: failure = "<"; goto assert_comparison; {
- assert_comparison:;
- binary_operands_t cmp = BINARY_OPERANDS(expr);
- type_t *lhs_t = get_type(env, cmp.lhs);
- type_t *rhs_t = get_type(env, cmp.rhs);
- type_t *operand_t;
- if (cmp.lhs->tag == Int && is_numeric_type(rhs_t)) {
- operand_t = rhs_t;
- } else if (cmp.rhs->tag == Int && is_numeric_type(lhs_t)) {
- operand_t = lhs_t;
- } else if (can_compile_to_type(env, cmp.rhs, lhs_t)) {
- operand_t = lhs_t;
- } else if (can_compile_to_type(env, cmp.lhs, rhs_t)) {
- operand_t = rhs_t;
- } else {
- code_err(ast, "I can't do comparisons between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
- }
-
- ast_t *lhs_var = FakeAST(InlineCCode, .chunks=new(ast_list_t, .ast=FakeAST(TextLiteral, Text("_lhs"))), .type=operand_t);
- ast_t *rhs_var = FakeAST(InlineCCode, .chunks=new(ast_list_t, .ast=FakeAST(TextLiteral, Text("_rhs"))), .type=operand_t);
- ast_t *var_comparison = new(ast_t, .file=expr->file, .start=expr->start, .end=expr->end, .tag=expr->tag,
- .__data.Equals={.lhs=lhs_var, .rhs=rhs_var});
- int64_t line = get_line_number(ast->file, ast->start);
- return Texts("{ // assertion\n",
- compile_declaration(operand_t, Text("_lhs")), " = ", compile_to_type(env, cmp.lhs, operand_t), ";\n",
- "\n#line ", String(line), "\n",
- compile_declaration(operand_t, Text("_rhs")), " = ", compile_to_type(env, cmp.rhs, operand_t), ";\n",
- "\n#line ", String(line), "\n",
- "if (!(", compile_condition(env, var_comparison), "))\n",
- "#line ", String(line), "\n",
- Texts(
- "fail_source(", quoted_str(ast->file->filename), ", ",
- String((int64_t)(expr->start - expr->file->text)), ", ",
- String((int64_t)(expr->end - expr->file->text)), ", ",
- message ? Texts("Text$as_c_string(", compile_to_type(env, message, Type(TextType)), ")")
- : Text("\"This assertion failed!\""), ", ",
- "\" (\", ", expr_as_text(Text("_lhs"), operand_t, Text("no")), ", "
- "\" ", failure, " \", ", expr_as_text(Text("_rhs"), operand_t, Text("no")), ", \")\");\n"),
- "}\n");
+ case GreaterThanOrEquals:
+ failure = "<";
+ goto assert_comparison;
+ {
+ assert_comparison:;
+ binary_operands_t cmp = BINARY_OPERANDS(expr);
+ type_t *lhs_t = get_type(env, cmp.lhs);
+ type_t *rhs_t = get_type(env, cmp.rhs);
+ type_t *operand_t;
+ if (cmp.lhs->tag == Int && is_numeric_type(rhs_t)) {
+ operand_t = rhs_t;
+ } else if (cmp.rhs->tag == Int && is_numeric_type(lhs_t)) {
+ operand_t = lhs_t;
+ } else if (can_compile_to_type(env, cmp.rhs, lhs_t)) {
+ operand_t = lhs_t;
+ } else if (can_compile_to_type(env, cmp.lhs, rhs_t)) {
+ operand_t = rhs_t;
+ } else {
+ code_err(ast, "I can't do comparisons between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
+ }
- }
+ ast_t *lhs_var =
+ FakeAST(InlineCCode, .chunks = new (ast_list_t, .ast = FakeAST(TextLiteral, Text("_lhs"))),
+ .type = operand_t);
+ ast_t *rhs_var =
+ FakeAST(InlineCCode, .chunks = new (ast_list_t, .ast = FakeAST(TextLiteral, Text("_rhs"))),
+ .type = operand_t);
+ ast_t *var_comparison = new (ast_t, .file = expr->file, .start = expr->start, .end = expr->end,
+ .tag = expr->tag, .__data.Equals = {.lhs = lhs_var, .rhs = rhs_var});
+ int64_t line = get_line_number(ast->file, ast->start);
+ return Texts("{ // assertion\n", compile_declaration(operand_t, Text("_lhs")), " = ",
+ compile_to_type(env, cmp.lhs, operand_t), ";\n", "\n#line ", String(line), "\n",
+ compile_declaration(operand_t, Text("_rhs")), " = ",
+ compile_to_type(env, cmp.rhs, operand_t), ";\n", "\n#line ", String(line), "\n", "if (!(",
+ compile_condition(env, var_comparison), "))\n", "#line ", String(line), "\n",
+ Texts("fail_source(", quoted_str(ast->file->filename), ", ",
+ String((int64_t)(expr->start - expr->file->text)), ", ",
+ String((int64_t)(expr->end - expr->file->text)), ", ",
+ message
+ ? Texts("Text$as_c_string(", compile_to_type(env, message, Type(TextType)), ")")
+ : Text("\"This assertion failed!\""),
+ ", ", "\" (\", ", expr_as_text(Text("_lhs"), operand_t, Text("no")),
+ ", "
+ "\" ",
+ failure, " \", ", expr_as_text(Text("_rhs"), operand_t, Text("no")), ", \")\");\n"),
+ "}\n");
+ }
default: {
int64_t line = get_line_number(ast->file, ast->start);
- return Texts(
- "if (!(", compile_condition(env, expr), "))\n",
- "#line ", String(line), "\n",
- "fail_source(", quoted_str(ast->file->filename), ", ",
- String((int64_t)(expr->start - expr->file->text)), ", ",
- String((int64_t)(expr->end - expr->file->text)), ", ",
- message ? Texts("Text$as_c_string(", compile_to_type(env, message, Type(TextType)), ")")
- : Text("\"This assertion failed!\""),
- ");\n");
+ return Texts("if (!(", compile_condition(env, expr), "))\n", "#line ", String(line), "\n", "fail_source(",
+ quoted_str(ast->file->filename), ", ", String((int64_t)(expr->start - expr->file->text)), ", ",
+ String((int64_t)(expr->end - expr->file->text)), ", ",
+ message ? Texts("Text$as_c_string(", compile_to_type(env, message, Type(TextType)), ")")
+ : Text("\"This assertion failed!\""),
+ ");\n");
}
}
}
@@ -1354,10 +1339,8 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
DeclareMatch(decl, ast, Declare);
const char *name = Match(decl->var, Var)->name;
if (streq(name, "_")) { // Explicit discard
- if (decl->value)
- return Texts("(void)", compile(env, decl->value), ";");
- else
- return EMPTY_TEXT;
+ if (decl->value) return Texts("(void)", compile(env, decl->value), ";");
+ else return EMPTY_TEXT;
} else {
type_t *t = decl->type ? parse_type_ast(env, decl->type) : get_type(env, decl->value);
if (t->tag == FunctionType) t = Type(ClosureType, t);
@@ -1377,7 +1360,10 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
&& value_type(get_type(env, Match(assign->targets->ast, Index)->indexed))->tag == TableType)
lhs_t = Match(lhs_t, OptionalType)->type;
if (has_stack_memory(lhs_t))
- code_err(ast, "Stack references cannot be assigned to variables because the variable's scope may outlive the scope of the stack memory.");
+ code_err(ast, "Stack references cannot be assigned to "
+ "variables because the "
+ "variable's scope may outlive the scope of the "
+ "stack memory.");
env_t *val_env = with_enum_scope(env, lhs_t);
Text_t val = compile_to_type(val_env, assign->values->ast, lhs_t);
return Texts(compile_assignment(env, assign->targets->ast, val), ";\n");
@@ -1385,13 +1371,17 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
Text_t code = Text("{ // Assignment\n");
int64_t i = 1;
- for (ast_list_t *value = assign->values, *target = assign->targets; value && target; value = value->next, target = target->next) {
+ for (ast_list_t *value = assign->values, *target = assign->targets; value && target;
+ value = value->next, target = target->next) {
type_t *lhs_t = get_type(env, target->ast);
if (target->ast->tag == Index && lhs_t->tag == OptionalType
&& value_type(get_type(env, Match(target->ast, Index)->indexed))->tag == TableType)
lhs_t = Match(lhs_t, OptionalType)->type;
if (has_stack_memory(lhs_t))
- code_err(ast, "Stack references cannot be assigned to variables because the variable's scope may outlive the scope of the stack memory.");
+ code_err(ast, "Stack references cannot be assigned to "
+ "variables because the "
+ "variable's scope may outlive the scope of the "
+ "stack memory.");
env_t *val_env = with_enum_scope(env, lhs_t);
Text_t val = compile_to_type(val_env, value->ast, lhs_t);
code = Texts(code, compile_type(lhs_t), " $", String(i), " = ", val, ";\n");
@@ -1439,11 +1429,24 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
return Texts(compile_lvalue(env, update->lhs), " %= ", compile_to_type(env, update->rhs, lhs_t), ";");
return compile_update_assignment(env, ast);
}
- case PowerUpdate: case Mod1Update: case ConcatUpdate: case LeftShiftUpdate: case UnsignedLeftShiftUpdate:
- case RightShiftUpdate: case UnsignedRightShiftUpdate: case AndUpdate: case OrUpdate: case XorUpdate: {
+ case PowerUpdate:
+ case Mod1Update:
+ case ConcatUpdate:
+ case LeftShiftUpdate:
+ case UnsignedLeftShiftUpdate:
+ case RightShiftUpdate:
+ case UnsignedRightShiftUpdate:
+ case AndUpdate:
+ case OrUpdate:
+ case XorUpdate: {
return compile_update_assignment(env, ast);
}
- case StructDef: case EnumDef: case LangDef: case Extend: case FunctionDef: case ConvertDef: {
+ case StructDef:
+ case EnumDef:
+ case LangDef:
+ case Extend:
+ case FunctionDef:
+ case ConvertDef: {
return EMPTY_TEXT;
}
case Skip: {
@@ -1460,20 +1463,16 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
++skip_label_count;
}
Text_t code = EMPTY_TEXT;
- for (deferral_t *deferred = env->deferred; deferred && deferred != ctx->deferred; deferred = deferred->next)
+ for (deferral_t *deferred = env->deferred; deferred && deferred != ctx->deferred;
+ deferred = deferred->next)
code = Texts(code, compile_statement(deferred->defer_env, deferred->block));
- if (code.length > 0)
- return Texts("{\n", code, "goto ", ctx->skip_label, ";\n}\n");
- else
- return Texts("goto ", ctx->skip_label, ";");
+ if (code.length > 0) return Texts("{\n", code, "goto ", ctx->skip_label, ";\n}\n");
+ else return Texts("goto ", ctx->skip_label, ";");
}
}
- if (env->loop_ctx)
- code_err(ast, "This is not inside any loop");
- else if (target)
- code_err(ast, "No loop target named '", target, "' was found");
- else
- return Text("continue;");
+ if (env->loop_ctx) code_err(ast, "This is not inside any loop");
+ else if (target) code_err(ast, "No loop target named '", target, "' was found");
+ else return Text("continue;");
}
case Stop: {
const char *target = Match(ast, Stop)->target;
@@ -1489,20 +1488,16 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
++stop_label_count;
}
Text_t code = EMPTY_TEXT;
- for (deferral_t *deferred = env->deferred; deferred && deferred != ctx->deferred; deferred = deferred->next)
+ for (deferral_t *deferred = env->deferred; deferred && deferred != ctx->deferred;
+ deferred = deferred->next)
code = Texts(code, compile_statement(deferred->defer_env, deferred->block));
- if (code.length > 0)
- return Texts("{\n", code, "goto ", ctx->stop_label, ";\n}\n");
- else
- return Texts("goto ", ctx->stop_label, ";");
+ if (code.length > 0) return Texts("{\n", code, "goto ", ctx->stop_label, ";\n}\n");
+ else return Texts("goto ", ctx->stop_label, ";");
}
}
- if (env->loop_ctx)
- code_err(ast, "This is not inside any loop");
- else if (target)
- code_err(ast, "No loop target named '", target, "' was found");
- else
- return Text("break;");
+ if (env->loop_ctx) code_err(ast, "This is not inside any loop");
+ else if (target) code_err(ast, "No loop target named '", target, "' was found");
+ else return Text("break;");
}
case Pass: return Text(";");
case Defer: {
@@ -1513,20 +1508,21 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
env_t *defer_env = fresh_scope(env);
Text_t code = EMPTY_TEXT;
for (int64_t i = 0; i < closed_vars.entries.length; i++) {
- struct { const char *name; binding_t *b; } *entry = closed_vars.entries.data + closed_vars.entries.stride*i;
- if (entry->b->type->tag == ModuleType)
- continue;
+ struct {
+ const char *name;
+ binding_t *b;
+ } *entry = closed_vars.entries.data + closed_vars.entries.stride * i;
+ if (entry->b->type->tag == ModuleType) continue;
if (Text$starts_with(entry->b->code, Text("userdata->"), NULL)) {
Table$str_set(defer_env->locals, entry->name, entry->b);
} else {
Text_t defer_name = Texts("defer$", String(++defer_id), "$", entry->name);
defer_id += 1;
- code = Texts(
- code, compile_declaration(entry->b->type, defer_name), " = ", entry->b->code, ";\n");
+ code = Texts(code, compile_declaration(entry->b->type, defer_name), " = ", entry->b->code, ";\n");
set_binding(defer_env, entry->name, entry->b->type, defer_name);
}
}
- env->deferred = new(deferral_t, .defer_env=defer_env, .block=body, .next=env->deferred);
+ env->deferred = new (deferral_t, .defer_env = defer_env, .block = body, .next = env->deferred);
return code;
}
case Return: {
@@ -1540,7 +1536,8 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
if (ret) {
if (env->fn_ret->tag == VoidType || env->fn_ret->tag == AbortType)
- code_err(ast, "This function is not supposed to return any values, according to its type signature");
+ code_err(ast, "This function is not supposed to return any values, "
+ "according to its type signature");
env = with_enum_scope(env, env->fn_ret);
Text_t value = compile_to_type(env, ret, env->fn_ret);
@@ -1560,34 +1557,31 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
DeclareMatch(while_, ast, While);
env_t *scope = fresh_scope(env);
loop_ctx_t loop_ctx = (loop_ctx_t){
- .loop_name="while",
- .deferred=scope->deferred,
- .next=env->loop_ctx,
+ .loop_name = "while",
+ .deferred = scope->deferred,
+ .next = env->loop_ctx,
};
scope->loop_ctx = &loop_ctx;
Text_t body = compile_statement(scope, while_->body);
- if (loop_ctx.skip_label.length > 0)
- body = Texts(body, "\n", loop_ctx.skip_label, ": continue;");
- Text_t loop = Texts("while (", while_->condition ? compile(scope, while_->condition) : Text("yes"), ") {\n\t", body, "\n}");
- if (loop_ctx.stop_label.length > 0)
- loop = Texts(loop, "\n", loop_ctx.stop_label, ":;");
+ if (loop_ctx.skip_label.length > 0) body = Texts(body, "\n", loop_ctx.skip_label, ": continue;");
+ Text_t loop = Texts("while (", while_->condition ? compile(scope, while_->condition) : Text("yes"), ") {\n\t",
+ body, "\n}");
+ if (loop_ctx.stop_label.length > 0) loop = Texts(loop, "\n", loop_ctx.stop_label, ":;");
return loop;
}
case Repeat: {
ast_t *body = Match(ast, Repeat)->body;
env_t *scope = fresh_scope(env);
loop_ctx_t loop_ctx = (loop_ctx_t){
- .loop_name="repeat",
- .deferred=scope->deferred,
- .next=env->loop_ctx,
+ .loop_name = "repeat",
+ .deferred = scope->deferred,
+ .next = env->loop_ctx,
};
scope->loop_ctx = &loop_ctx;
Text_t body_code = compile_statement(scope, body);
- if (loop_ctx.skip_label.length > 0)
- body_code = Texts(body_code, "\n", loop_ctx.skip_label, ": continue;");
+ if (loop_ctx.skip_label.length > 0) body_code = Texts(body_code, "\n", loop_ctx.skip_label, ": continue;");
Text_t loop = Texts("for (;;) {\n\t", body_code, "\n}");
- if (loop_ctx.stop_label.length > 0)
- loop = Texts(loop, "\n", loop_ctx.stop_label, ":;");
+ if (loop_ctx.stop_label.length > 0) loop = Texts(loop, "\n", loop_ctx.stop_label, ":;");
return loop;
}
case For: {
@@ -1595,50 +1589,48 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
// If we're iterating over a comprehension, that's actually just doing
// one loop, we don't need to compile the comprehension as a list
- // comprehension. This is a common case for reducers like `(+: i*2 for i in 5)`
- // or `(and) x.is_good() for x in xs`
+ // comprehension. This is a common case for reducers like `(+: i*2 for i
+ // in 5)` or `(and) x.is_good() for x in xs`
if (for_->iter->tag == Comprehension) {
DeclareMatch(comp, for_->iter, Comprehension);
ast_t *body = for_->body;
if (for_->vars) {
- if (for_->vars->next)
- code_err(for_->vars->next->ast, "This is too many variables for iteration");
+ if (for_->vars->next) code_err(for_->vars->next->ast, "This is too many variables for iteration");
body = WrapAST(
ast, Block,
- .statements=new(ast_list_t, .ast=WrapAST(ast, Declare, .var=for_->vars->ast, .value=comp->expr),
- .next=body->tag == Block ? Match(body, Block)->statements : new(ast_list_t, .ast=body)));
+ .statements = new (
+ ast_list_t, .ast = WrapAST(ast, Declare, .var = for_->vars->ast, .value = comp->expr),
+ .next = body->tag == Block ? Match(body, Block)->statements : new (ast_list_t, .ast = body)));
}
- if (comp->filter)
- body = WrapAST(for_->body, If, .condition=comp->filter, .body=body);
- ast_t *loop = WrapAST(ast, For, .vars=comp->vars, .iter=comp->iter, .body=body);
+ if (comp->filter) body = WrapAST(for_->body, If, .condition = comp->filter, .body = body);
+ ast_t *loop = WrapAST(ast, For, .vars = comp->vars, .iter = comp->iter, .body = body);
return compile_statement(env, loop);
}
env_t *body_scope = for_scope(env, ast);
loop_ctx_t loop_ctx = (loop_ctx_t){
- .loop_name="for",
- .loop_vars=for_->vars,
- .deferred=body_scope->deferred,
- .next=body_scope->loop_ctx,
+ .loop_name = "for",
+ .loop_vars = for_->vars,
+ .deferred = body_scope->deferred,
+ .next = body_scope->loop_ctx,
};
body_scope->loop_ctx = &loop_ctx;
// Naked means no enclosing braces:
Text_t naked_body = compile_inline_block(body_scope, for_->body);
- if (loop_ctx.skip_label.length > 0)
- naked_body = Texts(naked_body, "\n", loop_ctx.skip_label, ": continue;");
+ if (loop_ctx.skip_label.length > 0) naked_body = Texts(naked_body, "\n", loop_ctx.skip_label, ": continue;");
Text_t stop = loop_ctx.stop_label.length > 0 ? Texts("\n", loop_ctx.stop_label, ":;") : EMPTY_TEXT;
// Special case for improving performance for numeric iteration:
- if (for_->iter->tag == MethodCall && streq(Match(for_->iter, MethodCall)->name, "to") &&
- is_int_type(get_type(env, Match(for_->iter, MethodCall)->self))) {
+ if (for_->iter->tag == MethodCall && streq(Match(for_->iter, MethodCall)->name, "to")
+ && is_int_type(get_type(env, Match(for_->iter, MethodCall)->self))) {
// TODO: support other integer types
arg_ast_t *args = Match(for_->iter, MethodCall)->args;
if (!args) code_err(for_->iter, "to() needs at least one argument");
type_t *int_type = get_type(env, Match(for_->iter, MethodCall)->self);
- type_t *step_type = int_type->tag == ByteType ? Type(IntType, .bits=TYPE_IBITS8) : int_type;
+ type_t *step_type = int_type->tag == ByteType ? Type(IntType, .bits = TYPE_IBITS8) : int_type;
Text_t last = EMPTY_TEXT, step = EMPTY_TEXT, optional_step = EMPTY_TEXT;
if (!args->name || streq(args->name, "last")) {
@@ -1648,14 +1640,12 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
code_err(args->next->value, "Invalid argument name: ", args->next->name);
if (get_type(env, args->next->value)->tag == OptionalType)
optional_step = compile_to_type(env, args->next->value, Type(OptionalType, step_type));
- else
- step = compile_to_type(env, args->next->value, step_type);
+ else step = compile_to_type(env, args->next->value, step_type);
}
} else if (streq(args->name, "step")) {
if (get_type(env, args->value)->tag == OptionalType)
optional_step = compile_to_type(env, args->value, Type(OptionalType, step_type));
- else
- step = compile_to_type(env, args->value, step_type);
+ else step = compile_to_type(env, args->value, step_type);
if (args->next) {
if (args->next->name && !streq(args->next->name, "last"))
code_err(args->next->value, "Invalid argument name: ", args->next->name);
@@ -1663,52 +1653,57 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
}
}
- if (last.length == 0)
- code_err(for_->iter, "No `last` argument was given");
-
+ if (last.length == 0) code_err(for_->iter, "No `last` argument was given");
+
Text_t type_code = compile_type(int_type);
Text_t value = for_->vars ? compile(body_scope, for_->vars->ast) : Text("i");
if (int_type->tag == BigIntType) {
if (optional_step.length > 0)
- step = Texts("({ OptionalInt_t maybe_step = ", optional_step, "; maybe_step->small == 0 ? (Int$compare_value(last, first) >= 0 ? I_small(1) : I_small(-1)) : (Int_t)maybe_step; })");
+ step = Texts("({ OptionalInt_t maybe_step = ", optional_step,
+ "; maybe_step->small == 0 ? "
+ "(Int$compare_value(last, first) >= 0 "
+ "? I_small(1) : I_small(-1)) : (Int_t)maybe_step; "
+ "})");
else if (step.length == 0)
- step = Text("Int$compare_value(last, first) >= 0 ? I_small(1) : I_small(-1)");
- return Texts(
- "for (", type_code, " first = ", compile(env, Match(for_->iter, MethodCall)->self), ", ",
- value, " = first, last = ", last, ", step = ", step, "; "
- "Int$compare_value(", value, ", last) != Int$compare_value(step, I_small(0)); ",
- value, " = Int$plus(", value, ", step)) {\n"
- "\t", naked_body,
- "}",
- stop);
+ step = Text("Int$compare_value(last, first) >= 0 ? "
+ "I_small(1) : I_small(-1)");
+ return Texts("for (", type_code, " first = ", compile(env, Match(for_->iter, MethodCall)->self), ", ",
+ value, " = first, last = ", last, ", step = ", step,
+ "; "
+ "Int$compare_value(",
+ value, ", last) != Int$compare_value(step, I_small(0)); ", value, " = Int$plus(", value,
+ ", step)) {\n"
+ "\t",
+ naked_body, "}", stop);
} else {
if (optional_step.length > 0)
- step = Texts("({ ", compile_type(Type(OptionalType, step_type)), " maybe_step = ", optional_step, "; "
- "maybe_step.is_none ? (", type_code, ")(last >= first ? 1 : -1) : maybe_step.value; })");
- else if (step.length == 0)
- step = Texts("(", type_code, ")(last >= first ? 1 : -1)");
- return Texts(
- "for (", type_code, " first = ", compile(env, Match(for_->iter, MethodCall)->self), ", ",
- value, " = first, last = ", last, ", step = ", step, "; "
- "step > 0 ? ", value, " <= last : ", value, " >= last; ",
- value, " += step) {\n"
- "\t", naked_body,
- "}",
- stop);
+ step = Texts("({ ", compile_type(Type(OptionalType, step_type)), " maybe_step = ", optional_step,
+ "; "
+ "maybe_step.is_none ? (",
+ type_code, ")(last >= first ? 1 : -1) : maybe_step.value; })");
+ else if (step.length == 0) step = Texts("(", type_code, ")(last >= first ? 1 : -1)");
+ return Texts("for (", type_code, " first = ", compile(env, Match(for_->iter, MethodCall)->self), ", ",
+ value, " = first, last = ", last, ", step = ", step,
+ "; "
+ "step > 0 ? ",
+ value, " <= last : ", value, " >= last; ", value,
+ " += step) {\n"
+ "\t",
+ naked_body, "}", stop);
}
- } else if (for_->iter->tag == MethodCall && streq(Match(for_->iter, MethodCall)->name, "onward") &&
- get_type(env, Match(for_->iter, MethodCall)->self)->tag == BigIntType) {
+ } else if (for_->iter->tag == MethodCall && streq(Match(for_->iter, MethodCall)->name, "onward")
+ && get_type(env, Match(for_->iter, MethodCall)->self)->tag == BigIntType) {
// Special case for Int.onward()
arg_ast_t *args = Match(for_->iter, MethodCall)->args;
- arg_t *arg_spec = new(arg_t, .name="step", .type=INT_TYPE, .default_val=FakeAST(Int, .str="1"), .next=NULL);
+ arg_t *arg_spec =
+ new (arg_t, .name = "step", .type = INT_TYPE, .default_val = FakeAST(Int, .str = "1"), .next = NULL);
Text_t step = compile_arguments(env, for_->iter, arg_spec, args);
Text_t value = for_->vars ? compile(body_scope, for_->vars->ast) : Text("i");
- return Texts(
- "for (Int_t ", value, " = ", compile(env, Match(for_->iter, MethodCall)->self), ", ",
- "step = ", step, "; ; ", value, " = Int$plus(", value, ", step)) {\n"
- "\t", naked_body,
- "}",
- stop);
+ return Texts("for (Int_t ", value, " = ", compile(env, Match(for_->iter, MethodCall)->self), ", ",
+ "step = ", step, "; ; ", value, " = Int$plus(", value,
+ ", step)) {\n"
+ "\t",
+ naked_body, "}", stop);
}
type_t *iter_t = get_type(env, for_->iter);
@@ -1734,14 +1729,11 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
Text_t loop = EMPTY_TEXT;
loop = Texts(loop, "for (int64_t i = 1; i <= iterating.length; ++i)");
- if (index.length > 0)
- naked_body = Texts("Int_t ", index, " = I(i);\n", naked_body);
+ if (index.length > 0) naked_body = Texts("Int_t ", index, " = I(i);\n", naked_body);
if (value.length > 0) {
- loop = Texts(loop, "{\n",
- compile_declaration(item_t, value),
- " = *(", compile_type(item_t), "*)(iterating.data + (i-1)*iterating.stride);\n",
- naked_body, "\n}");
+ loop = Texts(loop, "{\n", compile_declaration(item_t, value), " = *(", compile_type(item_t),
+ "*)(iterating.data + (i-1)*iterating.stride);\n", naked_body, "\n}");
} else {
loop = Texts(loop, "{\n", naked_body, "\n}");
}
@@ -1751,38 +1743,37 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
if (iter_t->tag == PointerType) {
loop = Texts("{\n"
- "List_t *ptr = ", compile_to_pointer_depth(env, for_->iter, 1, false), ";\n"
- "\nLIST_INCREF(*ptr);\n"
- "List_t iterating = *ptr;\n",
- loop,
- stop,
- "\nLIST_DECREF(*ptr);\n"
- "}\n");
+ "List_t *ptr = ",
+ compile_to_pointer_depth(env, for_->iter, 1, false),
+ ";\n"
+ "\nLIST_INCREF(*ptr);\n"
+ "List_t iterating = *ptr;\n",
+ loop, stop,
+ "\nLIST_DECREF(*ptr);\n"
+ "}\n");
} else {
loop = Texts("{\n"
- "List_t iterating = ", compile_to_pointer_depth(env, for_->iter, 0, false), ";\n",
- loop,
- stop,
- "}\n");
+ "List_t iterating = ",
+ compile_to_pointer_depth(env, for_->iter, 0, false), ";\n", loop, stop, "}\n");
}
return loop;
}
- case SetType: case TableType: {
+ case SetType:
+ case TableType: {
Text_t loop = Text("for (int64_t i = 0; i < iterating.length; ++i) {\n");
if (for_->vars) {
if (iter_value_t->tag == SetType) {
- if (for_->vars->next)
- code_err(for_->vars->next->ast, "This is too many variables for this loop");
+ if (for_->vars->next) code_err(for_->vars->next->ast, "This is too many variables for this loop");
Text_t item = compile(body_scope, for_->vars->ast);
type_t *item_type = Match(iter_value_t, SetType)->item_type;
loop = Texts(loop, compile_declaration(item_type, item), " = *(", compile_type(item_type), "*)(",
- "iterating.data + i*iterating.stride);\n");
+ "iterating.data + i*iterating.stride);\n");
} else {
Text_t key = compile(body_scope, for_->vars->ast);
type_t *key_t = Match(iter_value_t, TableType)->key_type;
loop = Texts(loop, compile_declaration(key_t, key), " = *(", compile_type(key_t), "*)(",
- "iterating.data + i*iterating.stride);\n");
+ "iterating.data + i*iterating.stride);\n");
if (for_->vars->next) {
if (for_->vars->next->next)
@@ -1790,9 +1781,10 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
type_t *value_t = Match(iter_value_t, TableType)->value_type;
Text_t value = compile(body_scope, for_->vars->next->ast);
- Text_t value_offset = Texts("offsetof(struct { ", compile_declaration(key_t, Text("k")), "; ", compile_declaration(value_t, Text("v")), "; }, v)");
+ Text_t value_offset = Texts("offsetof(struct { ", compile_declaration(key_t, Text("k")), "; ",
+ compile_declaration(value_t, Text("v")), "; }, v)");
loop = Texts(loop, compile_declaration(value_t, value), " = *(", compile_type(value_t), "*)(",
- "iterating.data + i*iterating.stride + ", value_offset, ");\n");
+ "iterating.data + i*iterating.stride + ", value_offset, ");\n");
}
}
}
@@ -1804,20 +1796,16 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
}
if (iter_t->tag == PointerType) {
- loop = Texts(
- "{\n",
- "Table_t *t = ", compile_to_pointer_depth(env, for_->iter, 1, false), ";\n"
- "LIST_INCREF(t->entries);\n"
- "List_t iterating = t->entries;\n",
- loop,
- "LIST_DECREF(t->entries);\n"
- "}\n");
+ loop = Texts("{\n", "Table_t *t = ", compile_to_pointer_depth(env, for_->iter, 1, false),
+ ";\n"
+ "LIST_INCREF(t->entries);\n"
+ "List_t iterating = t->entries;\n",
+ loop,
+ "LIST_DECREF(t->entries);\n"
+ "}\n");
} else {
- loop = Texts(
- "{\n",
- "List_t iterating = (", compile_to_pointer_depth(env, for_->iter, 0, false), ").entries;\n",
- loop,
- "}\n");
+ loop = Texts("{\n", "List_t iterating = (", compile_to_pointer_depth(env, for_->iter, 0, false),
+ ").entries;\n", loop, "}\n");
}
return loop;
}
@@ -1826,52 +1814,50 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
if (for_->iter->tag == Int) {
const char *str = Match(for_->iter, Int)->str;
Int_t int_val = Int$from_str(str);
- if (int_val.small == 0)
- code_err(for_->iter, "Failed to parse this integer");
+ if (int_val.small == 0) code_err(for_->iter, "Failed to parse this integer");
mpz_t i;
mpz_init_set_int(i, int_val);
- if (mpz_cmpabs_ui(i, BIGGEST_SMALL_INT) <= 0)
- n = Text$from_str(mpz_get_str(NULL, 10, i));
- else
- goto big_n;
-
+ if (mpz_cmpabs_ui(i, BIGGEST_SMALL_INT) <= 0) n = Text$from_str(mpz_get_str(NULL, 10, i));
+ else goto big_n;
if (for_->empty && mpz_cmp_si(i, 0) <= 0) {
return compile_statement(env, for_->empty);
} else {
- return Texts(
- "for (int64_t i = 1; i <= ", n, "; ++i) {\n",
- for_->vars ? Texts("\tInt_t ", compile(body_scope, for_->vars->ast), " = I_small(i);\n") : EMPTY_TEXT,
- "\t", naked_body,
- "}\n",
- stop, "\n");
+ return Texts("for (int64_t i = 1; i <= ", n, "; ++i) {\n",
+ for_->vars
+ ? Texts("\tInt_t ", compile(body_scope, for_->vars->ast), " = I_small(i);\n")
+ : EMPTY_TEXT,
+ "\t", naked_body, "}\n", stop, "\n");
}
}
- big_n:
+ big_n:
n = compile_to_pointer_depth(env, for_->iter, 0, false);
Text_t i = for_->vars ? compile(body_scope, for_->vars->ast) : Text("i");
Text_t n_var = for_->vars ? Texts("max", i) : Text("n");
if (for_->empty) {
- return Texts(
- "{\n"
- "Int_t ", n_var, " = ", n, ";\n"
- "if (Int$compare_value(", n_var, ", I(0)) > 0) {\n"
- "for (Int_t ", i, " = I(1); Int$compare_value(", i, ", ", n_var, ") <= 0; ", i, " = Int$plus(", i, ", I(1))) {\n",
- "\t", naked_body,
- "}\n"
- "} else ", compile_statement(env, for_->empty),
- stop, "\n"
- "}\n");
+ return Texts("{\n"
+ "Int_t ",
+ n_var, " = ", n,
+ ";\n"
+ "if (Int$compare_value(",
+ n_var,
+ ", I(0)) > 0) {\n"
+ "for (Int_t ",
+ i, " = I(1); Int$compare_value(", i, ", ", n_var, ") <= 0; ", i, " = Int$plus(", i,
+ ", I(1))) {\n", "\t", naked_body,
+ "}\n"
+ "} else ",
+ compile_statement(env, for_->empty), stop,
+ "\n"
+ "}\n");
} else {
- return Texts(
- "for (Int_t ", i, " = I(1), ", n_var, " = ", n, "; Int$compare_value(", i, ", ", n_var, ") <= 0; ", i, " = Int$plus(", i, ", I(1))) {\n",
- "\t", naked_body,
- "}\n",
- stop, "\n");
+ return Texts("for (Int_t ", i, " = I(1), ", n_var, " = ", n, "; Int$compare_value(", i, ", ", n_var,
+ ") <= 0; ", i, " = Int$plus(", i, ", I(1))) {\n", "\t", naked_body, "}\n", stop, "\n");
}
}
- case FunctionType: case ClosureType: {
+ case FunctionType:
+ case ClosureType: {
// Iterator function:
Text_t code = Text("{\n");
@@ -1879,53 +1865,63 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
if (is_idempotent(for_->iter)) {
next_fn = compile_to_pointer_depth(env, for_->iter, 0, false);
} else {
- code = Texts(code, compile_declaration(iter_value_t, Text("next")), " = ", compile_to_pointer_depth(env, for_->iter, 0, false), ";\n");
+ code = Texts(code, compile_declaration(iter_value_t, Text("next")), " = ",
+ compile_to_pointer_depth(env, for_->iter, 0, false), ";\n");
next_fn = Text("next");
}
- __typeof(iter_value_t->__data.FunctionType) *fn = iter_value_t->tag == ClosureType ? Match(Match(iter_value_t, ClosureType)->fn, FunctionType) : Match(iter_value_t, FunctionType);
+ __typeof(iter_value_t->__data.FunctionType) *fn =
+ iter_value_t->tag == ClosureType ? Match(Match(iter_value_t, ClosureType)->fn, FunctionType)
+ : Match(iter_value_t, FunctionType);
Text_t get_next;
if (iter_value_t->tag == ClosureType) {
type_t *fn_t = Match(iter_value_t, ClosureType)->fn;
arg_t *closure_fn_args = NULL;
for (arg_t *arg = Match(fn_t, FunctionType)->args; arg; arg = arg->next)
- closure_fn_args = new(arg_t, .name=arg->name, .type=arg->type, .default_val=arg->default_val, .next=closure_fn_args);
- closure_fn_args = new(arg_t, .name="userdata", .type=Type(PointerType, .pointed=Type(MemoryType)), .next=closure_fn_args);
+ closure_fn_args = new (arg_t, .name = arg->name, .type = arg->type, .default_val = arg->default_val,
+ .next = closure_fn_args);
+ closure_fn_args = new (arg_t, .name = "userdata",
+ .type = Type(PointerType, .pointed = Type(MemoryType)), .next = closure_fn_args);
REVERSE_LIST(closure_fn_args);
- Text_t fn_type_code = compile_type(Type(FunctionType, .args=closure_fn_args, .ret=Match(fn_t, FunctionType)->ret));
+ Text_t fn_type_code =
+ compile_type(Type(FunctionType, .args = closure_fn_args, .ret = Match(fn_t, FunctionType)->ret));
get_next = Texts("((", fn_type_code, ")", next_fn, ".fn)(", next_fn, ".userdata)");
} else {
get_next = Texts(next_fn, "()");
}
if (fn->ret->tag == OptionalType) {
- // Use an optional variable `cur` for each iteration step, which will be checked for none
+ // Use an optional variable `cur` for each iteration step, which
+ // will be checked for none
code = Texts(code, compile_declaration(fn->ret, Text("cur")), ";\n");
get_next = Texts("(cur=", get_next, ", !", check_none(fn->ret, Text("cur")), ")");
if (for_->vars) {
- naked_body = Texts(
- compile_declaration(Match(fn->ret, OptionalType)->type, Texts("_$", Match(for_->vars->ast, Var)->name)),
- " = ", optional_into_nonnone(fn->ret, Text("cur")), ";\n",
- naked_body);
+ naked_body = Texts(compile_declaration(Match(fn->ret, OptionalType)->type,
+ Texts("_$", Match(for_->vars->ast, Var)->name)),
+ " = ", optional_into_nonnone(fn->ret, Text("cur")), ";\n", naked_body);
}
if (for_->empty) {
- code = Texts(code, "if (", get_next, ") {\n"
- "\tdo{\n\t\t", naked_body, "\t} while(", get_next, ");\n"
- "} else {\n\t", compile_statement(env, for_->empty), "}", stop, "\n}\n");
+ code = Texts(code, "if (", get_next,
+ ") {\n"
+ "\tdo{\n\t\t",
+ naked_body, "\t} while(", get_next,
+ ");\n"
+ "} else {\n\t",
+ compile_statement(env, for_->empty), "}", stop, "\n}\n");
} else {
code = Texts(code, "while(", get_next, ") {\n\t", naked_body, "}\n", stop, "\n}\n");
}
} else {
if (for_->vars) {
- naked_body = Texts(
- compile_declaration(fn->ret, Texts("_$", Match(for_->vars->ast, Var)->name)),
- " = ", get_next, ";\n", naked_body);
+ naked_body = Texts(compile_declaration(fn->ret, Texts("_$", Match(for_->vars->ast, Var)->name)),
+ " = ", get_next, ";\n", naked_body);
} else {
naked_body = Texts(get_next, ";\n", naked_body);
}
if (for_->empty)
- code_err(for_->empty, "This iteration loop will always have values, so this block will never run");
+ code_err(for_->empty, "This iteration loop will always have values, "
+ "so this block will never run");
code = Texts(code, "for (;;) {\n\t", naked_body, "}\n", stop, "\n}\n");
}
@@ -1938,8 +1934,7 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
DeclareMatch(if_, ast, If);
ast_t *condition = if_->condition;
if (condition->tag == Declare) {
- if (Match(condition, Declare)->value == NULL)
- code_err(condition, "This declaration must have a value");
+ if (Match(condition, Declare)->value == NULL) code_err(condition, "This declaration must have a value");
env_t *truthy_scope = fresh_scope(env);
Text_t code = Texts("IF_DECLARE(", compile_statement(truthy_scope, condition), ", ");
bind_statement(truthy_scope, condition);
@@ -1947,13 +1942,11 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
code = Texts(code, compile_condition(truthy_scope, var), ", ");
type_t *cond_t = get_type(truthy_scope, var);
if (cond_t->tag == OptionalType) {
- set_binding(truthy_scope, Match(var, Var)->name,
- Match(cond_t, OptionalType)->type,
+ set_binding(truthy_scope, Match(var, Var)->name, Match(cond_t, OptionalType)->type,
optional_into_nonnone(cond_t, compile(truthy_scope, var)));
}
code = Texts(code, compile_statement(truthy_scope, if_->body), ")");
- if (if_->else_body)
- code = Texts(code, "\nelse ", compile_statement(env, if_->else_body));
+ if (if_->else_body) code = Texts(code, "\nelse ", compile_statement(env, if_->else_body));
return code;
} else {
Text_t code = Texts("if (", compile_condition(env, condition), ")");
@@ -1961,13 +1954,11 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
type_t *cond_t = get_type(env, condition);
if (condition->tag == Var && cond_t->tag == OptionalType) {
truthy_scope = fresh_scope(env);
- set_binding(truthy_scope, Match(condition, Var)->name,
- Match(cond_t, OptionalType)->type,
+ set_binding(truthy_scope, Match(condition, Var)->name, Match(cond_t, OptionalType)->type,
optional_into_nonnone(cond_t, compile(truthy_scope, condition)));
}
code = Texts(code, compile_statement(truthy_scope, if_->body));
- if (if_->else_body)
- code = Texts(code, "\nelse ", compile_statement(env, if_->else_body));
+ if (if_->else_body) code = Texts(code, "\nelse ", compile_statement(env, if_->else_body));
return code;
}
}
@@ -1975,21 +1966,19 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
return Texts("{\n", compile_inline_block(env, ast), "}\n");
}
case Comprehension: {
- if (!env->comprehension_action)
- code_err(ast, "I don't know what to do with this comprehension!");
+ if (!env->comprehension_action) code_err(ast, "I don't know what to do with this comprehension!");
DeclareMatch(comp, ast, Comprehension);
if (comp->expr->tag == Comprehension) { // Nested comprehension
- ast_t *body = comp->filter ? WrapAST(ast, If, .condition=comp->filter, .body=comp->expr) : comp->expr;
- ast_t *loop = WrapAST(ast, For, .vars=comp->vars, .iter=comp->iter, .body=body);
+ ast_t *body = comp->filter ? WrapAST(ast, If, .condition = comp->filter, .body = comp->expr) : comp->expr;
+ ast_t *loop = WrapAST(ast, For, .vars = comp->vars, .iter = comp->iter, .body = body);
return compile_statement(env, loop);
}
// List/Set/Table comprehension:
- comprehension_body_t get_body = (void*)env->comprehension_action->fn;
+ comprehension_body_t get_body = (void *)env->comprehension_action->fn;
ast_t *body = get_body(comp->expr, env->comprehension_action->userdata);
- if (comp->filter)
- body = WrapAST(comp->expr, If, .condition=comp->filter, .body=body);
- ast_t *loop = WrapAST(ast, For, .vars=comp->vars, .iter=comp->iter, .body=body);
+ if (comp->filter) body = WrapAST(comp->expr, If, .condition = comp->filter, .body = body);
+ ast_t *loop = WrapAST(ast, For, .vars = comp->vars, .iter = comp->iter, .body = body);
return compile_statement(env, loop);
}
case Extern: return EMPTY_TEXT;
@@ -2017,9 +2006,10 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
module_info_t mod = get_module_info(ast);
glob_t tm_files;
const char *folder = mod.version ? String(mod.name, "_", mod.version) : mod.name;
- if (glob(String(TOMO_PREFIX"/share/tomo_"TOMO_VERSION"/installed/", folder, "/[!._0-9]*.tm"), GLOB_TILDE, NULL, &tm_files) != 0) {
- if (!try_install_module(mod))
- code_err(ast, "Could not find library");
+ if (glob(String(TOMO_PREFIX "/share/tomo_" TOMO_VERSION "/installed/", folder, "/[!._0-9]*.tm"), GLOB_TILDE,
+ NULL, &tm_files)
+ != 0) {
+ if (!try_install_module(mod)) code_err(ast, "Could not find library");
}
Text_t initialization = EMPTY_TEXT;
@@ -2027,8 +2017,7 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
for (size_t i = 0; i < tm_files.gl_pathc; i++) {
const char *filename = tm_files.gl_pathv[i];
initialization = Texts(
- initialization,
- with_source_info(env, ast, Texts("$initialize", get_id_suffix(filename), "();\n")));
+ initialization, with_source_info(env, ast, Texts("$initialize", get_id_suffix(filename), "();\n")));
}
globfree(&tm_files);
return initialization;
@@ -2037,7 +2026,8 @@ static Text_t _compile_statement(env_t *env, ast_t *ast)
}
}
default:
- // print("Is discardable: ", ast_to_sexp_str(ast), " ==> ", is_discardable(env, ast));
+ // print("Is discardable: ", ast_to_sexp_str(ast), " ==> ",
+ // is_discardable(env, ast));
if (!is_discardable(env, ast))
code_err(ast, "The ", type_to_str(get_type(env, ast)), " result of this statement cannot be discarded");
return Texts("(void)", compile(env, ast), ";");
@@ -2049,15 +2039,18 @@ Text_t compile_statement(env_t *env, ast_t *ast) {
return with_source_info(env, ast, stmt);
}
-Text_t expr_as_text(Text_t expr, type_t *t, Text_t color)
-{
+Text_t expr_as_text(Text_t expr, type_t *t, Text_t color) {
switch (t->tag) {
case MemoryType: return Texts("Memory$as_text(stack(", expr, "), ", color, ", &Memory$info)");
case BoolType:
- // NOTE: this cannot use stack(), since bools may actually be bit fields:
- return Texts("Bool$as_text((Bool_t[1]){", expr, "}, ", color, ", &Bool$info)");
+ // NOTE: this cannot use stack(), since bools may actually be bit
+ // fields:
+ return Texts("Bool$as_text((Bool_t[1]){", expr, "}, ", color, ", &Bool$info)");
case CStringType: return Texts("CString$as_text(stack(", expr, "), ", color, ", &CString$info)");
- case BigIntType: case IntType: case ByteType: case NumType: {
+ case BigIntType:
+ case IntType:
+ case ByteType:
+ case NumType: {
Text_t name = type_to_text(t);
return Texts(name, "$as_text(stack(", expr, "), ", color, ", &", name, "$info)");
}
@@ -2065,25 +2058,24 @@ Text_t expr_as_text(Text_t expr, type_t *t, Text_t color)
case ListType: return Texts("List$as_text(stack(", expr, "), ", color, ", ", compile_type_info(t), ")");
case SetType: return Texts("Table$as_text(stack(", expr, "), ", color, ", ", compile_type_info(t), ")");
case TableType: return Texts("Table$as_text(stack(", expr, "), ", color, ", ", compile_type_info(t), ")");
- case FunctionType: case ClosureType: return Texts("Func$as_text(stack(", expr, "), ", color, ", ", compile_type_info(t), ")");
+ case FunctionType:
+ case ClosureType: return Texts("Func$as_text(stack(", expr, "), ", color, ", ", compile_type_info(t), ")");
case PointerType: return Texts("Pointer$as_text(stack(", expr, "), ", color, ", ", compile_type_info(t), ")");
case OptionalType: return Texts("Optional$as_text(stack(", expr, "), ", color, ", ", compile_type_info(t), ")");
- case StructType: case EnumType:
- return Texts("generic_as_text(stack(", expr, "), ", color, ", ", compile_type_info(t), ")");
+ case StructType:
+ case EnumType: return Texts("generic_as_text(stack(", expr, "), ", color, ", ", compile_type_info(t), ")");
default: compiler_err(NULL, NULL, NULL, "Stringifying is not supported for ", type_to_str(t));
}
return EMPTY_TEXT;
}
-Text_t compile_text(env_t *env, ast_t *ast, Text_t color)
-{
+Text_t compile_text(env_t *env, ast_t *ast, Text_t color) {
type_t *t = get_type(env, ast);
Text_t expr = compile(env, ast);
return expr_as_text(expr, t, color);
}
-Text_t compile_to_pointer_depth(env_t *env, ast_t *ast, int64_t target_depth, bool needs_incref)
-{
+Text_t compile_to_pointer_depth(env_t *env, ast_t *ast, int64_t target_depth, bool needs_incref) {
Text_t val = compile(env, ast);
type_t *t = get_type(env, ast);
int64_t depth = 0;
@@ -2092,16 +2084,13 @@ Text_t compile_to_pointer_depth(env_t *env, ast_t *ast, int64_t target_depth, bo
// Passing a literal value won't trigger an incref, because it's ephemeral,
// e.g. [10, 20].reversed()
- if (t->tag != PointerType && needs_incref && !can_be_mutated(env, ast))
- needs_incref = false;
+ if (t->tag != PointerType && needs_incref && !can_be_mutated(env, ast)) needs_incref = false;
while (depth != target_depth) {
if (depth < target_depth) {
- if (ast->tag == Var && target_depth == 1)
- val = Texts("(&", val, ")");
- else
- code_err(ast, "This should be a pointer, not ", type_to_str(get_type(env, ast)));
- t = Type(PointerType, .pointed=t, .is_stack=true);
+ if (ast->tag == Var && target_depth == 1) val = Texts("(&", val, ")");
+ else code_err(ast, "This should be a pointer, not ", type_to_str(get_type(env, ast)));
+ t = Type(PointerType, .pointed = t, .is_stack = true);
++depth;
} else {
DeclareMatch(ptr, t, PointerType);
@@ -2116,16 +2105,13 @@ Text_t compile_to_pointer_depth(env_t *env, ast_t *ast, int64_t target_depth, bo
t = ptr->pointed;
}
- if (needs_incref && t->tag == ListType)
- val = Texts("LIST_COPY(", val, ")");
- else if (needs_incref && (t->tag == TableType || t->tag == SetType))
- val = Texts("TABLE_COPY(", val, ")");
+ if (needs_incref && t->tag == ListType) val = Texts("LIST_COPY(", val, ")");
+ else if (needs_incref && (t->tag == TableType || t->tag == SetType)) val = Texts("TABLE_COPY(", val, ")");
return val;
}
-Text_t compile_to_type(env_t *env, ast_t *ast, type_t *t)
-{
+Text_t compile_to_type(env_t *env, ast_t *ast, type_t *t) {
assert(!is_incomplete_type(t));
if (ast->tag == Int && is_numeric_type(non_optional(t))) {
return compile_int_to_type(env, ast, t);
@@ -2137,10 +2123,11 @@ Text_t compile_to_type(env_t *env, ast_t *ast, type_t *t)
default: code_err(ast, "This is not a valid number bit width");
}
} else if (ast->tag == None) {
- if (t->tag != OptionalType)
- code_err(ast, "This is not supposed to be an optional type");
+ if (t->tag != OptionalType) code_err(ast, "This is not supposed to be an optional type");
else if (Match(t, OptionalType)->type == NULL)
- code_err(ast, "I don't know what kind of `none` this is supposed to be!\nPlease tell me by declaring a variable like `foo : Type = none`");
+ code_err(ast, "I don't know what kind of `none` this is supposed to "
+ "be!\nPlease "
+ "tell me by declaring a variable like `foo : Type = none`");
return compile_none(t);
} else if (t->tag == PointerType && (ast->tag == HeapAllocate || ast->tag == StackReference)) {
return compile_typed_allocation(env, ast, t);
@@ -2166,15 +2153,17 @@ Text_t compile_to_type(env_t *env, ast_t *ast, type_t *t)
if (ast->tag == MethodCall) {
DeclareMatch(methodcall, ast, MethodCall);
type_t *self_type = get_type(env, methodcall->self);
- // Currently, this is only implemented for cases where you have the return type
- // and the self type equal to each other, because that's the main case I care
- // about with list and set methods (e.g. `List.sorted()`)
+ // Currently, this is only implemented for cases where you have the
+ // return type and the self type equal to each other, because that's the
+ // main case I care about with list and set methods (e.g.
+ // `List.sorted()`)
if (is_incomplete_type(self_type) && type_eq(self_type, actual)) {
type_t *completed_self = most_complete_type(self_type, t);
if (completed_self) {
- ast_t *explicit_self = WrapAST(methodcall->self, ExplicitlyTyped, .ast=methodcall->self, .type=completed_self);
- ast_t *new_methodcall = WrapAST(ast, MethodCall, .self=explicit_self,
- .name=methodcall->name, .args=methodcall->args);
+ ast_t *explicit_self =
+ WrapAST(methodcall->self, ExplicitlyTyped, .ast = methodcall->self, .type = completed_self);
+ ast_t *new_methodcall =
+ WrapAST(ast, MethodCall, .self = explicit_self, .name = methodcall->name, .args = methodcall->args);
return compile_to_type(env, new_methodcall, t);
}
}
@@ -2186,11 +2175,10 @@ Text_t compile_to_type(env_t *env, ast_t *ast, type_t *t)
if (!is_incomplete_type(actual)) {
Text_t code = compile(env, ast);
- if (promote(env, ast, &code, actual, t))
- return code;
+ if (promote(env, ast, &code, actual, t)) return code;
}
- arg_ast_t *constructor_args = new(arg_ast_t, .value=ast);
+ arg_ast_t *constructor_args = new (arg_ast_t, .value = ast);
binding_t *constructor = get_constructor(env, t, constructor_args, true);
if (constructor) {
arg_t *arg_spec = Match(constructor->type, FunctionType)->args;
@@ -2200,25 +2188,21 @@ Text_t compile_to_type(env_t *env, ast_t *ast, type_t *t)
code_err(ast, "I expected a ", type_to_str(t), " here, but this is a ", type_to_str(actual));
}
-Text_t compile_typed_list(env_t *env, ast_t *ast, type_t *list_type)
-{
+Text_t compile_typed_list(env_t *env, ast_t *ast, type_t *list_type) {
DeclareMatch(list, ast, List);
- if (!list->items)
- return Text("(List_t){.length=0}");
+ if (!list->items) return Text("(List_t){.length=0}");
type_t *item_type = Match(list_type, ListType)->item_type;
int64_t n = 0;
for (ast_list_t *item = list->items; item; item = item->next) {
++n;
- if (item->ast->tag == Comprehension)
- goto list_comprehension;
+ if (item->ast->tag == Comprehension) goto list_comprehension;
}
{
env_t *scope = item_type->tag == EnumType ? with_enum_scope(env, item_type) : env;
- if (is_incomplete_type(item_type))
- code_err(ast, "This list's type can't be inferred!");
+ if (is_incomplete_type(item_type)) code_err(ast, "This list's type can't be inferred!");
Text_t code = Texts("TypedListN(", compile_type(item_type), ", ", String(n));
for (ast_list_t *item = list->items; item; item = item->next) {
code = Texts(code, ", ", compile_to_type(scope, item->ast, item_type));
@@ -2226,48 +2210,39 @@ Text_t compile_typed_list(env_t *env, ast_t *ast, type_t *list_type)
return Texts(code, ")");
}
- list_comprehension:
- {
- env_t *scope = item_type->tag == EnumType ? with_enum_scope(env, item_type) : fresh_scope(env);
- static int64_t comp_num = 1;
- const char *comprehension_name = String("list$", comp_num++);
- ast_t *comprehension_var = LiteralCode(Texts("&", comprehension_name),
- .type=Type(PointerType, .pointed=list_type, .is_stack=true));
- Closure_t comp_action = {.fn=add_to_list_comprehension, .userdata=comprehension_var};
- scope->comprehension_action = &comp_action;
- Text_t code = Texts("({ List_t ", comprehension_name, " = {};");
- // set_binding(scope, comprehension_name, list_type, comprehension_name);
- for (ast_list_t *item = list->items; item; item = item->next) {
- if (item->ast->tag == Comprehension)
- code = Texts(code, "\n", compile_statement(scope, item->ast));
- else
- code = Texts(code, compile_statement(env, add_to_list_comprehension(item->ast, comprehension_var)));
- }
- code = Texts(code, " ", comprehension_name, "; })");
- return code;
+list_comprehension: {
+ env_t *scope = item_type->tag == EnumType ? with_enum_scope(env, item_type) : fresh_scope(env);
+ static int64_t comp_num = 1;
+ const char *comprehension_name = String("list$", comp_num++);
+ ast_t *comprehension_var =
+ LiteralCode(Texts("&", comprehension_name), .type = Type(PointerType, .pointed = list_type, .is_stack = true));
+ Closure_t comp_action = {.fn = add_to_list_comprehension, .userdata = comprehension_var};
+ scope->comprehension_action = &comp_action;
+ Text_t code = Texts("({ List_t ", comprehension_name, " = {};");
+ // set_binding(scope, comprehension_name, list_type, comprehension_name);
+ for (ast_list_t *item = list->items; item; item = item->next) {
+ if (item->ast->tag == Comprehension) code = Texts(code, "\n", compile_statement(scope, item->ast));
+ else code = Texts(code, compile_statement(env, add_to_list_comprehension(item->ast, comprehension_var)));
}
+ code = Texts(code, " ", comprehension_name, "; })");
+ return code;
+}
}
-Text_t compile_typed_set(env_t *env, ast_t *ast, type_t *set_type)
-{
+Text_t compile_typed_set(env_t *env, ast_t *ast, type_t *set_type) {
DeclareMatch(set, ast, Set);
- if (!set->items)
- return Text("((Table_t){})");
+ if (!set->items) return Text("((Table_t){})");
type_t *item_type = Match(set_type, SetType)->item_type;
int64_t n = 0;
for (ast_list_t *item = set->items; item; item = item->next) {
++n;
- if (item->ast->tag == Comprehension)
- goto set_comprehension;
+ if (item->ast->tag == Comprehension) goto set_comprehension;
}
-
+
{ // No comprehension:
- Text_t code = Texts("Set(",
- compile_type(item_type), ", ",
- compile_type_info(item_type), ", ",
- String(n));
+ Text_t code = Texts("Set(", compile_type(item_type), ", ", compile_type_info(item_type), ", ", String(n));
env_t *scope = item_type->tag == EnumType ? with_enum_scope(env, item_type) : env;
for (ast_list_t *item = set->items; item; item = item->next) {
code = Texts(code, ", ", compile_to_type(scope, item->ast, item_type));
@@ -2275,34 +2250,29 @@ Text_t compile_typed_set(env_t *env, ast_t *ast, type_t *set_type)
return Texts(code, ")");
}
- set_comprehension:
- {
- static int64_t comp_num = 1;
- env_t *scope = item_type->tag == EnumType ? with_enum_scope(env, item_type) : fresh_scope(env);
- const char *comprehension_name = String("set$", comp_num++);
- ast_t *comprehension_var = LiteralCode(Texts("&", comprehension_name),
- .type=Type(PointerType, .pointed=set_type, .is_stack=true));
- Text_t code = Texts("({ Table_t ", comprehension_name, " = {};");
- Closure_t comp_action = {.fn=add_to_set_comprehension, .userdata=comprehension_var};
- scope->comprehension_action = &comp_action;
- for (ast_list_t *item = set->items; item; item = item->next) {
- if (item->ast->tag == Comprehension)
- code = Texts(code, "\n", compile_statement(scope, item->ast));
- else
- code = Texts(code, compile_statement(env, add_to_set_comprehension(item->ast, comprehension_var)));
- }
- code = Texts(code, " ", comprehension_name, "; })");
- return code;
+set_comprehension: {
+ static int64_t comp_num = 1;
+ env_t *scope = item_type->tag == EnumType ? with_enum_scope(env, item_type) : fresh_scope(env);
+ const char *comprehension_name = String("set$", comp_num++);
+ ast_t *comprehension_var =
+ LiteralCode(Texts("&", comprehension_name), .type = Type(PointerType, .pointed = set_type, .is_stack = true));
+ Text_t code = Texts("({ Table_t ", comprehension_name, " = {};");
+ Closure_t comp_action = {.fn = add_to_set_comprehension, .userdata = comprehension_var};
+ scope->comprehension_action = &comp_action;
+ for (ast_list_t *item = set->items; item; item = item->next) {
+ if (item->ast->tag == Comprehension) code = Texts(code, "\n", compile_statement(scope, item->ast));
+ else code = Texts(code, compile_statement(env, add_to_set_comprehension(item->ast, comprehension_var)));
}
+ code = Texts(code, " ", comprehension_name, "; })");
+ return code;
+}
}
-Text_t compile_typed_table(env_t *env, ast_t *ast, type_t *table_type)
-{
+Text_t compile_typed_table(env_t *env, ast_t *ast, type_t *table_type) {
DeclareMatch(table, ast, Table);
if (!table->entries) {
Text_t code = Text("((Table_t){");
- if (table->fallback)
- code = Texts(code, ".fallback=heap(", compile(env, table->fallback),")");
+ if (table->fallback) code = Texts(code, ".fallback=heap(", compile(env, table->fallback), ")");
return Texts(code, "})");
}
@@ -2313,22 +2283,16 @@ Text_t compile_typed_table(env_t *env, ast_t *ast, type_t *table_type)
code_err(ast, "Tables whose values are optional (", type_to_str(value_t), ") are not currently supported.");
for (ast_list_t *entry = table->entries; entry; entry = entry->next) {
- if (entry->ast->tag == Comprehension)
- goto table_comprehension;
+ if (entry->ast->tag == Comprehension) goto table_comprehension;
}
{ // No comprehension:
env_t *key_scope = key_t->tag == EnumType ? with_enum_scope(env, key_t) : env;
env_t *value_scope = value_t->tag == EnumType ? with_enum_scope(env, value_t) : env;
- Text_t code = Texts("Table(",
- compile_type(key_t), ", ",
- compile_type(value_t), ", ",
- compile_type_info(key_t), ", ",
- compile_type_info(value_t));
- if (table->fallback)
- code = Texts(code, ", /*fallback:*/ heap(", compile(env, table->fallback), ")");
- else
- code = Texts(code, ", /*fallback:*/ NULL");
+ Text_t code = Texts("Table(", compile_type(key_t), ", ", compile_type(value_t), ", ", compile_type_info(key_t),
+ ", ", compile_type_info(value_t));
+ if (table->fallback) code = Texts(code, ", /*fallback:*/ heap(", compile(env, table->fallback), ")");
+ else code = Texts(code, ", /*fallback:*/ NULL");
size_t n = 0;
for (ast_list_t *entry = table->entries; entry; entry = entry->next)
@@ -2338,40 +2302,35 @@ Text_t compile_typed_table(env_t *env, ast_t *ast, type_t *table_type)
for (ast_list_t *entry = table->entries; entry; entry = entry->next) {
DeclareMatch(e, entry->ast, TableEntry);
code = Texts(code, ",\n\t{", compile_to_type(key_scope, e->key, key_t), ", ",
- compile_to_type(value_scope, e->value, value_t), "}");
+ compile_to_type(value_scope, e->value, value_t), "}");
}
return Texts(code, ")");
}
- table_comprehension:
- {
- static int64_t comp_num = 1;
- env_t *scope = fresh_scope(env);
- const char *comprehension_name = String("table$", comp_num++);
- ast_t *comprehension_var = LiteralCode(Texts("&", comprehension_name),
- .type=Type(PointerType, .pointed=table_type, .is_stack=true));
+table_comprehension: {
+ static int64_t comp_num = 1;
+ env_t *scope = fresh_scope(env);
+ const char *comprehension_name = String("table$", comp_num++);
+ ast_t *comprehension_var =
+ LiteralCode(Texts("&", comprehension_name), .type = Type(PointerType, .pointed = table_type, .is_stack = true));
- Text_t code = Texts("({ Table_t ", comprehension_name, " = {");
- if (table->fallback)
- code = Texts(code, ".fallback=heap(", compile(env, table->fallback), "), ");
+ Text_t code = Texts("({ Table_t ", comprehension_name, " = {");
+ if (table->fallback) code = Texts(code, ".fallback=heap(", compile(env, table->fallback), "), ");
- code = Texts(code, "};");
+ code = Texts(code, "};");
- Closure_t comp_action = {.fn=add_to_table_comprehension, .userdata=comprehension_var};
- scope->comprehension_action = &comp_action;
- for (ast_list_t *entry = table->entries; entry; entry = entry->next) {
- if (entry->ast->tag == Comprehension)
- code = Texts(code, "\n", compile_statement(scope, entry->ast));
- else
- code = Texts(code, compile_statement(env, add_to_table_comprehension(entry->ast, comprehension_var)));
- }
- code = Texts(code, " ", comprehension_name, "; })");
- return code;
+ Closure_t comp_action = {.fn = add_to_table_comprehension, .userdata = comprehension_var};
+ scope->comprehension_action = &comp_action;
+ for (ast_list_t *entry = table->entries; entry; entry = entry->next) {
+ if (entry->ast->tag == Comprehension) code = Texts(code, "\n", compile_statement(scope, entry->ast));
+ else code = Texts(code, compile_statement(env, add_to_table_comprehension(entry->ast, comprehension_var)));
}
+ code = Texts(code, " ", comprehension_name, "; })");
+ return code;
+}
}
-Text_t compile_typed_allocation(env_t *env, ast_t *ast, type_t *pointer_type)
-{
+Text_t compile_typed_allocation(env_t *env, ast_t *ast, type_t *pointer_type) {
// TODO: for constructors, do new(T, ...) instead of heap((T){...})
type_t *pointed = Match(pointer_type, PointerType)->pointed;
switch (ast->tag) {
@@ -2382,16 +2341,14 @@ Text_t compile_typed_allocation(env_t *env, ast_t *ast, type_t *pointer_type)
ast_t *subject = Match(ast, StackReference)->value;
if (can_be_mutated(env, subject) && type_eq(pointed, get_type(env, subject)))
return Texts("(&", compile_lvalue(env, subject), ")");
- else
- return Texts("stack(", compile_to_type(env, subject, pointed), ")");
+ else return Texts("stack(", compile_to_type(env, subject, pointed), ")");
}
default: code_err(ast, "Not an allocation!");
}
return EMPTY_TEXT;
}
-Text_t compile_int_to_type(env_t *env, ast_t *ast, type_t *target)
-{
+Text_t compile_int_to_type(env_t *env, ast_t *ast, type_t *target) {
if (ast->tag != Int) {
Text_t code = compile(env, ast);
type_t *actual_type = get_type(env, ast);
@@ -2400,16 +2357,14 @@ Text_t compile_int_to_type(env_t *env, ast_t *ast, type_t *target)
return code;
}
- if (target->tag == BigIntType)
- return compile(env, ast);
+ if (target->tag == BigIntType) return compile(env, ast);
if (target->tag == OptionalType && Match(target, OptionalType)->type)
return compile_int_to_type(env, ast, Match(target, OptionalType)->type);
const char *literal = Match(ast, Int)->str;
OptionalInt_t int_val = Int$from_str(literal);
- if (int_val.small == 0)
- code_err(ast, "Failed to parse this integer");
+ if (int_val.small == 0) code_err(ast, "Failed to parse this integer");
mpz_t i;
mpz_init_set_int(i, int_val);
@@ -2424,8 +2379,7 @@ Text_t compile_int_to_type(env_t *env, ast_t *ast, type_t *target)
}
if (target->tag == ByteType) {
- if (mpz_cmp_si(i, UINT8_MAX) <= 0 && mpz_cmp_si(i, 0) >= 0)
- return Texts("(Byte_t)(", c_literal, ")");
+ if (mpz_cmp_si(i, UINT8_MAX) <= 0 && mpz_cmp_si(i, 0) >= 0) return Texts("(Byte_t)(", c_literal, ")");
code_err(ast, "This integer cannot fit in a byte");
} else if (target->tag == NumType) {
if (Match(target, NumType)->bits == TYPE_NBITS64) {
@@ -2437,22 +2391,17 @@ Text_t compile_int_to_type(env_t *env, ast_t *ast, type_t *target)
int64_t target_bits = (int64_t)Match(target, IntType)->bits;
switch (target_bits) {
case TYPE_IBITS64:
- if (mpz_cmp_si(i, INT64_MIN) == 0)
- return Text("I64(INT64_MIN)");
- if (mpz_cmp_si(i, INT64_MAX) <= 0 && mpz_cmp_si(i, INT64_MIN) >= 0)
- return Texts("I64(", c_literal, "L)");
+ if (mpz_cmp_si(i, INT64_MIN) == 0) return Text("I64(INT64_MIN)");
+ if (mpz_cmp_si(i, INT64_MAX) <= 0 && mpz_cmp_si(i, INT64_MIN) >= 0) return Texts("I64(", c_literal, "L)");
break;
case TYPE_IBITS32:
- if (mpz_cmp_si(i, INT32_MAX) <= 0 && mpz_cmp_si(i, INT32_MIN) >= 0)
- return Texts("I32(", c_literal, ")");
+ if (mpz_cmp_si(i, INT32_MAX) <= 0 && mpz_cmp_si(i, INT32_MIN) >= 0) return Texts("I32(", c_literal, ")");
break;
case TYPE_IBITS16:
- if (mpz_cmp_si(i, INT16_MAX) <= 0 && mpz_cmp_si(i, INT16_MIN) >= 0)
- return Texts("I16(", c_literal, ")");
+ if (mpz_cmp_si(i, INT16_MAX) <= 0 && mpz_cmp_si(i, INT16_MIN) >= 0) return Texts("I16(", c_literal, ")");
break;
case TYPE_IBITS8:
- if (mpz_cmp_si(i, INT8_MAX) <= 0 && mpz_cmp_si(i, INT8_MIN) >= 0)
- return Texts("I8(", c_literal, ")");
+ if (mpz_cmp_si(i, INT8_MAX) <= 0 && mpz_cmp_si(i, INT8_MIN) >= 0) return Texts("I8(", c_literal, ")");
break;
default: break;
}
@@ -2463,13 +2412,12 @@ Text_t compile_int_to_type(env_t *env, ast_t *ast, type_t *target)
return EMPTY_TEXT;
}
-Text_t compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_t *call_args)
-{
+Text_t compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_t *call_args) {
Table_t used_args = {};
Text_t code = EMPTY_TEXT;
- env_t *default_scope = new(env_t);
+ env_t *default_scope = new (env_t);
*default_scope = *env;
- default_scope->locals = new(Table_t, .fallback=env->namespace_bindings ? env->namespace_bindings : env->globals);
+ default_scope->locals = new (Table_t, .fallback = env->namespace_bindings ? env->namespace_bindings : env->globals);
for (arg_t *spec_arg = spec_args; spec_arg; spec_arg = spec_arg->next) {
int64_t i = 1;
// Find keyword:
@@ -2481,12 +2429,10 @@ Text_t compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_
value = compile_int_to_type(env, call_arg->value, spec_arg->type);
} else if (spec_arg->type->tag == NumType && call_arg->value->tag == Int) {
OptionalInt_t int_val = Int$from_str(Match(call_arg->value, Int)->str);
- if (int_val.small == 0)
- code_err(call_arg->value, "Failed to parse this integer");
+ if (int_val.small == 0) code_err(call_arg->value, "Failed to parse this integer");
if (Match(spec_arg->type, NumType)->bits == TYPE_NBITS64)
value = Text$from_str(String(hex_double(Num$from_int(int_val, false))));
- else
- value = Text$from_str(String(hex_double((double)Num32$from_int(int_val, false)), "f"));
+ else value = Text$from_str(String(hex_double((double)Num32$from_int(int_val, false)), "f"));
} else {
env_t *arg_env = with_enum_scope(env, spec_arg->type);
value = compile_maybe_incref(arg_env, call_arg->value, spec_arg->type);
@@ -2508,12 +2454,10 @@ Text_t compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_
value = compile_int_to_type(env, call_arg->value, spec_arg->type);
} else if (spec_arg->type->tag == NumType && call_arg->value->tag == Int) {
OptionalInt_t int_val = Int$from_str(Match(call_arg->value, Int)->str);
- if (int_val.small == 0)
- code_err(call_arg->value, "Failed to parse this integer");
+ if (int_val.small == 0) code_err(call_arg->value, "Failed to parse this integer");
if (Match(spec_arg->type, NumType)->bits == TYPE_NBITS64)
value = Text$from_str(String(hex_double(Num$from_int(int_val, false))));
- else
- value = Text$from_str(String(hex_double((double)Num32$from_int(int_val, false)), "f"));
+ else value = Text$from_str(String(hex_double((double)Num32$from_int(int_val, false)), "f"));
} else {
env_t *arg_env = with_enum_scope(env, spec_arg->type);
value = compile_maybe_incref(arg_env, call_arg->value, spec_arg->type);
@@ -2534,7 +2478,8 @@ Text_t compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_
assert(spec_arg->name);
code_err(call_ast, "The required argument '", spec_arg->name, "' was not provided");
- found_it: continue;
+ found_it:
+ continue;
}
int64_t i = 1;
@@ -2544,15 +2489,13 @@ Text_t compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_
code_err(call_arg->value, "There is no argument with the name '", call_arg->name, "'");
} else {
const char *pseudoname = String(i++);
- if (!Table$str_get(used_args, pseudoname))
- code_err(call_arg->value, "This is one argument too many!");
+ if (!Table$str_get(used_args, pseudoname)) code_err(call_arg->value, "This is one argument too many!");
}
}
return code;
}
-Text_t compile_text_literal(Text_t literal)
-{
+Text_t compile_text_literal(Text_t literal) {
Text_t code = Text("\"");
const char *utf8 = Text$as_c_string(literal);
for (const char *p = utf8; *p; p++) {
@@ -2569,8 +2512,8 @@ Text_t compile_text_literal(Text_t literal)
if (isprint(*p)) {
code = Texts(code, Text$from_strn(p, 1));
} else {
- uint8_t byte = *(uint8_t*)p;
- code = Texts(code, "\\x", String(hex(byte, .no_prefix=true, .uppercase=true, .digits=2)), "\"\"");
+ uint8_t byte = *(uint8_t *)p;
+ code = Texts(code, "\\x", String(hex(byte, .no_prefix = true, .uppercase = true, .digits = 2)), "\"\"");
}
break;
}
@@ -2579,27 +2522,21 @@ Text_t compile_text_literal(Text_t literal)
return Texts(code, "\"");
}
-PUREFUNC static bool string_literal_is_all_ascii(Text_t literal)
-{
+PUREFUNC static bool string_literal_is_all_ascii(Text_t literal) {
TextIter_t state = NEW_TEXT_ITER_STATE(literal);
for (int64_t i = 0; i < literal.length; i++) {
int32_t g = Text$get_grapheme_fast(&state, i);
- if (g < 0 || g > 127 || !isascii(g))
- return false;
+ if (g < 0 || g > 127 || !isascii(g)) return false;
}
return true;
}
-Text_t compile_none(type_t *t)
-{
- if (t == NULL)
- compiler_err(NULL, NULL, NULL, "I can't compile a `none` value with no type");
+Text_t compile_none(type_t *t) {
+ if (t == NULL) compiler_err(NULL, NULL, NULL, "I can't compile a `none` value with no type");
- if (t->tag == OptionalType)
- t = Match(t, OptionalType)->type;
+ if (t->tag == OptionalType) t = Match(t, OptionalType)->type;
- if (t == NULL)
- compiler_err(NULL, NULL, NULL, "I can't compile a `none` value with no type");
+ if (t == NULL) compiler_err(NULL, NULL, NULL, "I can't compile a `none` value with no type");
if (t == PATH_TYPE) return Text("NONE_PATH");
else if (t == PATH_TYPE_TYPE) return Text("((OptionalPathType_t){})");
@@ -2626,7 +2563,7 @@ Text_t compile_none(type_t *t)
case PointerType: return Texts("((", compile_type(t), ")NULL)");
case ClosureType: return Text("NONE_CLOSURE");
case NumType: return Text("nan(\"none\")");
- case StructType: return Texts("((", compile_type(Type(OptionalType, .type=t)), "){.is_none=true})");
+ case StructType: return Texts("((", compile_type(Type(OptionalType, .type = t)), "){.is_none=true})");
case EnumType: {
env_t *enum_env = Match(t, EnumType)->env;
return Texts("((", compile_type(t), "){", namespace_name(enum_env, enum_env->namespace, Text("none")), "})");
@@ -2636,13 +2573,10 @@ Text_t compile_none(type_t *t)
return EMPTY_TEXT;
}
-Text_t compile_empty(type_t *t)
-{
- if (t == NULL)
- compiler_err(NULL, NULL, NULL, "I can't compile a value with no type");
+Text_t compile_empty(type_t *t) {
+ if (t == NULL) compiler_err(NULL, NULL, NULL, "I can't compile a value with no type");
- if (t->tag == OptionalType)
- return compile_none(t);
+ if (t->tag == OptionalType) return compile_none(t);
if (t == PATH_TYPE) return Text("NONE_PATH");
else if (t == PATH_TYPE_TYPE) return Text("((OptionalPathType_t){})");
@@ -2662,13 +2596,15 @@ Text_t compile_empty(type_t *t)
case ByteType: return Text("((Byte_t)0)");
case BoolType: return Text("((Bool_t)no)");
case ListType: return Text("((List_t){})");
- case TableType: case SetType: return Text("((Table_t){})");
+ case TableType:
+ case SetType: return Text("((Table_t){})");
case TextType: return Text("Text(\"\")");
case CStringType: return Text("\"\"");
case PointerType: {
DeclareMatch(ptr, t, PointerType);
Text_t empty_pointed = compile_empty(ptr->pointed);
- return empty_pointed.length == 0 ? EMPTY_TEXT : Texts(ptr->is_stack ? Text("stack(") : Text("heap("), empty_pointed, ")");
+ return empty_pointed.length == 0 ? EMPTY_TEXT
+ : Texts(ptr->is_stack ? Text("stack(") : Text("heap("), empty_pointed, ")");
}
case NumType: {
return Match(t, NumType)->bits == TYPE_NBITS32 ? Text("N32(0.0f)") : Text("N64(0.0)");
@@ -2677,15 +2613,12 @@ Text_t compile_empty(type_t *t)
DeclareMatch(struct_, t, StructType);
Text_t code = Texts("((", compile_type(t), "){");
for (arg_t *field = struct_->fields; field; field = field->next) {
- Text_t empty_field = field->default_val
- ? compile(struct_->env, field->default_val)
- : compile_empty(field->type);
- if (empty_field.length == 0)
- return EMPTY_TEXT;
+ Text_t empty_field =
+ field->default_val ? compile(struct_->env, field->default_val) : compile_empty(field->type);
+ if (empty_field.length == 0) return EMPTY_TEXT;
code = Texts(code, empty_field);
- if (field->next)
- code = Texts(code, ", ");
+ if (field->next) code = Texts(code, ", ");
}
return Texts(code, "})");
}
@@ -2695,19 +2628,17 @@ Text_t compile_empty(type_t *t)
assert(tag);
assert(tag->type);
if (Match(tag->type, StructType)->fields)
- return Texts("((", compile_type(t), "){.$tag=", String(tag->tag_value), ", .", tag->name, "=", compile_empty(tag->type), "})");
- else if (enum_has_fields(t))
- return Texts("((", compile_type(t), "){.$tag=", String(tag->tag_value), "})");
- else
- return Texts("((", compile_type(t), ")", String(tag->tag_value), ")");
+ return Texts("((", compile_type(t), "){.$tag=", String(tag->tag_value), ", .", tag->name, "=",
+ compile_empty(tag->type), "})");
+ else if (enum_has_fields(t)) return Texts("((", compile_type(t), "){.$tag=", String(tag->tag_value), "})");
+ else return Texts("((", compile_type(t), ")", String(tag->tag_value), ")");
}
default: return EMPTY_TEXT;
}
return EMPTY_TEXT;
}
-static Text_t compile_declared_value(env_t *env, ast_t *declare_ast)
-{
+static Text_t compile_declared_value(env_t *env, ast_t *declare_ast) {
DeclareMatch(decl, declare_ast, Declare);
type_t *t = decl->type ? parse_type_ast(env, decl->type) : get_type(env, decl->value);
@@ -2724,30 +2655,27 @@ static Text_t compile_declared_value(env_t *env, ast_t *declare_ast)
} else {
Text_t val_code = compile_empty(t);
if (val_code.length == 0)
- code_err(declare_ast, "This type (", type_to_str(t), ") cannot be uninitialized. You must provide a value.");
+ code_err(declare_ast, "This type (", type_to_str(t),
+ ") cannot be uninitialized. You must provide a value.");
return val_code;
}
}
-ast_t *add_to_table_comprehension(ast_t *entry, ast_t *subject)
-{
+ast_t *add_to_table_comprehension(ast_t *entry, ast_t *subject) {
DeclareMatch(e, entry, TableEntry);
- return WrapAST(entry, MethodCall, .name="set", .self=subject,
- .args=new(arg_ast_t, .value=e->key, .next=new(arg_ast_t, .value=e->value)));
+ return WrapAST(entry, MethodCall, .name = "set", .self = subject,
+ .args = new (arg_ast_t, .value = e->key, .next = new (arg_ast_t, .value = e->value)));
}
-ast_t *add_to_list_comprehension(ast_t *item, ast_t *subject)
-{
- return WrapAST(item, MethodCall, .name="insert", .self=subject, .args=new(arg_ast_t, .value=item));
+ast_t *add_to_list_comprehension(ast_t *item, ast_t *subject) {
+ return WrapAST(item, MethodCall, .name = "insert", .self = subject, .args = new (arg_ast_t, .value = item));
}
-ast_t *add_to_set_comprehension(ast_t *item, ast_t *subject)
-{
- return WrapAST(item, MethodCall, .name="add", .self=subject, .args=new(arg_ast_t, .value=item));
+ast_t *add_to_set_comprehension(ast_t *item, ast_t *subject) {
+ return WrapAST(item, MethodCall, .name = "add", .self = subject, .args = new (arg_ast_t, .value = item));
}
-Text_t compile(env_t *env, ast_t *ast)
-{
+Text_t compile(env_t *env, ast_t *ast) {
switch (ast->tag) {
case None: {
code_err(ast, "I can't figure out what this `none`'s type is!");
@@ -2755,16 +2683,14 @@ Text_t compile(env_t *env, ast_t *ast)
case Bool: return Match(ast, Bool)->b ? Text("yes") : Text("no");
case Var: {
binding_t *b = get_binding(env, Match(ast, Var)->name);
- if (b)
- return b->code.length > 0 ? b->code : Texts("_$", Match(ast, Var)->name);
+ if (b) return b->code.length > 0 ? b->code : Texts("_$", Match(ast, Var)->name);
// return Texts("_$", Match(ast, Var)->name);
code_err(ast, "I don't know of any variable by this name");
}
case Int: {
const char *str = Match(ast, Int)->str;
OptionalInt_t int_val = Int$from_str(str);
- if (int_val.small == 0)
- code_err(ast, "Failed to parse this integer");
+ if (int_val.small == 0) code_err(ast, "Failed to parse this integer");
mpz_t i;
mpz_init_set_int(i, int_val);
if (mpz_cmpabs_ui(i, BIGGEST_SMALL_INT) <= 0) {
@@ -2786,21 +2712,16 @@ Text_t compile(env_t *env, ast_t *ast)
if (b && b->type->tag == FunctionType) {
DeclareMatch(fn, b->type, FunctionType);
if (fn->args && can_compile_to_type(env, value, get_arg_type(env, fn->args)))
- return Texts(b->code, "(", compile_arguments(env, ast, fn->args, new(arg_ast_t, .value=value)), ")");
+ return Texts(b->code, "(", compile_arguments(env, ast, fn->args, new (arg_ast_t, .value = value)), ")");
}
- if (t->tag == BoolType)
- return Texts("!(", compile(env, value), ")");
- else if (t->tag == IntType || t->tag == ByteType)
- return Texts("~(", compile(env, value), ")");
- else if (t->tag == ListType)
- return Texts("((", compile(env, value), ").length == 0)");
+ if (t->tag == BoolType) return Texts("!(", compile(env, value), ")");
+ else if (t->tag == IntType || t->tag == ByteType) return Texts("~(", compile(env, value), ")");
+ else if (t->tag == ListType) return Texts("((", compile(env, value), ").length == 0)");
else if (t->tag == SetType || t->tag == TableType)
return Texts("((", compile(env, value), ").entries.length == 0)");
- else if (t->tag == TextType)
- return Texts("(", compile(env, value), ".length == 0)");
- else if (t->tag == OptionalType)
- return check_none(t, compile(env, value));
+ else if (t->tag == TextType) return Texts("(", compile(env, value), ".length == 0)");
+ else if (t->tag == OptionalType) return check_none(t, compile(env, value));
code_err(ast, "I don't know how to negate values of type ", type_to_str(t));
}
@@ -2811,16 +2732,15 @@ Text_t compile(env_t *env, ast_t *ast)
if (b && b->type->tag == FunctionType) {
DeclareMatch(fn, b->type, FunctionType);
if (fn->args && can_compile_to_type(env, value, get_arg_type(env, fn->args)))
- return Texts(b->code, "(", compile_arguments(env, ast, fn->args, new(arg_ast_t, .value=value)), ")");
+ return Texts(b->code, "(", compile_arguments(env, ast, fn->args, new (arg_ast_t, .value = value)), ")");
}
- if (t->tag == IntType || t->tag == NumType)
- return Texts("-(", compile(env, value), ")");
+ if (t->tag == IntType || t->tag == NumType) return Texts("-(", compile(env, value), ")");
code_err(ast, "I don't know how to get the negative value of type ", type_to_str(t));
-
}
- case HeapAllocate: case StackReference: {
+ case HeapAllocate:
+ case StackReference: {
return compile_typed_allocation(env, ast, get_type(env, ast));
}
case Optional: {
@@ -2833,20 +2753,32 @@ Text_t compile(env_t *env, ast_t *ast)
type_t *t = get_type(env, value);
Text_t value_code = compile(env, value);
int64_t line = get_line_number(ast->file, ast->start);
- return Texts("({ ", compile_declaration(t, Text("opt")), " = ", value_code, "; ",
- "if unlikely (", check_none(t, Text("opt")), ")\n",
- "#line ", String(line), "\n",
- "fail_source(", quoted_str(ast->file->filename), ", ",
- String((int64_t)(value->start - value->file->text)), ", ",
- String((int64_t)(value->end - value->file->text)), ", ",
- "\"This was expected to be a value, but it's none\");\n",
- optional_into_nonnone(t, Text("opt")), "; })");
- }
- case Power: case Multiply: case Divide: case Mod: case Mod1: case Plus: case Minus: case Concat:
- case LeftShift: case UnsignedLeftShift: case RightShift: case UnsignedRightShift: case And: case Or: case Xor: {
+ return Texts("({ ", compile_declaration(t, Text("opt")), " = ", value_code, "; ", "if unlikely (",
+ check_none(t, Text("opt")), ")\n", "#line ", String(line), "\n", "fail_source(",
+ quoted_str(ast->file->filename), ", ", String((int64_t)(value->start - value->file->text)), ", ",
+ String((int64_t)(value->end - value->file->text)), ", ",
+ "\"This was expected to be a value, but it's none\");\n", optional_into_nonnone(t, Text("opt")),
+ "; })");
+ }
+ case Power:
+ case Multiply:
+ case Divide:
+ case Mod:
+ case Mod1:
+ case Plus:
+ case Minus:
+ case Concat:
+ case LeftShift:
+ case UnsignedLeftShift:
+ case RightShift:
+ case UnsignedRightShift:
+ case And:
+ case Or:
+ case Xor: {
return compile_binary_op(env, ast);
}
- case Equals: case NotEquals: {
+ case Equals:
+ case NotEquals: {
binary_operands_t binop = BINARY_OPERANDS(ast);
type_t *lhs_t = get_type(env, binop.lhs);
@@ -2871,14 +2803,22 @@ Text_t compile(env_t *env, ast_t *ast)
switch (operand_t->tag) {
case BigIntType:
return Texts(ast->tag == Equals ? EMPTY_TEXT : Text("!"), "Int$equal_value(", lhs, ", ", rhs, ")");
- case BoolType: case ByteType: case IntType: case NumType: case PointerType: case FunctionType:
- return Texts("(", lhs, ast->tag == Equals ? " == " : " != ", rhs, ")");
+ case BoolType:
+ case ByteType:
+ case IntType:
+ case NumType:
+ case PointerType:
+ case FunctionType: return Texts("(", lhs, ast->tag == Equals ? " == " : " != ", rhs, ")");
default:
- return Texts(ast->tag == Equals ? EMPTY_TEXT : Text("!"),
- "generic_equal(stack(", lhs, "), stack(", rhs, "), ", compile_type_info(operand_t), ")");
+ return Texts(ast->tag == Equals ? EMPTY_TEXT : Text("!"), "generic_equal(stack(", lhs, "), stack(", rhs,
+ "), ", compile_type_info(operand_t), ")");
}
}
- case LessThan: case LessThanOrEquals: case GreaterThan: case GreaterThanOrEquals: case Compare: {
+ case LessThan:
+ case LessThanOrEquals:
+ case GreaterThan:
+ case GreaterThanOrEquals:
+ case Compare: {
binary_operands_t cmp = BINARY_OPERANDS(ast);
type_t *lhs_t = get_type(env, cmp.lhs);
@@ -2900,49 +2840,47 @@ Text_t compile(env_t *env, ast_t *ast)
Text_t rhs = compile_to_type(env, cmp.rhs, operand_t);
if (ast->tag == Compare)
- return Texts("generic_compare(stack(", lhs, "), stack(", rhs, "), ",
- compile_type_info(operand_t), ")");
+ return Texts("generic_compare(stack(", lhs, "), stack(", rhs, "), ", compile_type_info(operand_t), ")");
const char *op = binop_operator(ast->tag);
switch (operand_t->tag) {
- case BigIntType:
- return Texts("(Int$compare_value(", lhs, ", ", rhs, ") ", op, " 0)");
- case BoolType: case ByteType: case IntType: case NumType: case PointerType: case FunctionType:
- return Texts("(", lhs, " ", op, " ", rhs, ")");
+ case BigIntType: return Texts("(Int$compare_value(", lhs, ", ", rhs, ") ", op, " 0)");
+ case BoolType:
+ case ByteType:
+ case IntType:
+ case NumType:
+ case PointerType:
+ case FunctionType: return Texts("(", lhs, " ", op, " ", rhs, ")");
default:
- return Texts("(generic_compare(stack(", lhs, "), stack(", rhs, "), ",
- compile_type_info(operand_t), ") ", op, " 0)");
+ return Texts("(generic_compare(stack(", lhs, "), stack(", rhs, "), ", compile_type_info(operand_t), ") ",
+ op, " 0)");
}
}
case TextLiteral: {
- Text_t literal = Match(ast, TextLiteral)->text;
- if (literal.length == 0)
- return Text("EMPTY_TEXT");
+ Text_t literal = Match(ast, TextLiteral)->text;
+ if (literal.length == 0) return Text("EMPTY_TEXT");
- if (string_literal_is_all_ascii(literal))
- return Texts("Text(", compile_text_literal(literal), ")");
- else
- return Texts("Text$from_str(", compile_text_literal(literal), ")");
+ if (string_literal_is_all_ascii(literal)) return Texts("Text(", compile_text_literal(literal), ")");
+ else return Texts("Text$from_str(", compile_text_literal(literal), ")");
}
case TextJoin: {
const char *lang = Match(ast, TextJoin)->lang;
Text_t colorize = Match(ast, TextJoin)->colorize ? Text("yes") : Text("no");
type_t *text_t = lang ? Table$str_get(*env->types, lang) : TEXT_TYPE;
- if (!text_t || text_t->tag != TextType)
- code_err(ast, quoted(lang), " is not a valid text language name");
+ if (!text_t || text_t->tag != TextType) code_err(ast, quoted(lang), " is not a valid text language name");
Text_t lang_constructor;
- if (!lang || streq(lang, "Text"))
- lang_constructor = Text("Text");
+ if (!lang || streq(lang, "Text")) lang_constructor = Text("Text");
else
- lang_constructor = namespace_name(Match(text_t, TextType)->env, Match(text_t, TextType)->env->namespace->parent, Text$from_str(lang));
+ lang_constructor = namespace_name(Match(text_t, TextType)->env,
+ Match(text_t, TextType)->env->namespace->parent, Text$from_str(lang));
ast_list_t *chunks = Match(ast, TextJoin)->children;
if (!chunks) {
return Texts(lang_constructor, "(\"\")");
} else if (!chunks->next && chunks->ast->tag == TextLiteral) {
- Text_t literal = Match(chunks->ast, TextLiteral)->text;
+ Text_t literal = Match(chunks->ast, TextLiteral)->text;
if (string_literal_is_all_ascii(literal))
return Texts(lang_constructor, "(", compile_text_literal(literal), ")");
return Texts("((", compile_type(text_t), ")", compile(env, chunks->ast), ")");
@@ -2954,28 +2892,26 @@ Text_t compile(env_t *env, ast_t *ast)
if (chunk->ast->tag == TextLiteral || type_eq(chunk_t, text_t)) {
chunk_code = compile(env, chunk->ast);
} else {
- binding_t *constructor = get_constructor(env, text_t, new(arg_ast_t, .value=chunk->ast),
- env->current_type != NULL && type_eq(env->current_type, text_t));
+ binding_t *constructor =
+ get_constructor(env, text_t, new (arg_ast_t, .value = chunk->ast),
+ env->current_type != NULL && type_eq(env->current_type, text_t));
if (constructor) {
arg_t *arg_spec = Match(constructor->type, FunctionType)->args;
- arg_ast_t *args = new(arg_ast_t, .value=chunk->ast);
+ arg_ast_t *args = new (arg_ast_t, .value = chunk->ast);
chunk_code = Texts(constructor->code, "(", compile_arguments(env, ast, arg_spec, args), ")");
} else if (type_eq(text_t, TEXT_TYPE)) {
- if (chunk_t->tag == TextType)
- chunk_code = compile(env, chunk->ast);
- else
- chunk_code = compile_text(env, chunk->ast, colorize);
+ if (chunk_t->tag == TextType) chunk_code = compile(env, chunk->ast);
+ else chunk_code = compile_text(env, chunk->ast, colorize);
} else {
- code_err(chunk->ast, "I don't know how to convert ", type_to_str(chunk_t), " to ", type_to_str(text_t));
+ code_err(chunk->ast, "I don't know how to convert ", type_to_str(chunk_t), " to ",
+ type_to_str(text_t));
}
}
code = Texts(code, chunk_code);
if (chunk->next) code = Texts(code, ", ");
}
- if (chunks->next)
- return Texts(lang_constructor, "s(", code, ")");
- else
- return code;
+ if (chunks->next) return Texts(lang_constructor, "s(", code, ")");
+ else return code;
}
}
case Path: {
@@ -2983,8 +2919,7 @@ Text_t compile(env_t *env, ast_t *ast)
}
case Block: {
ast_list_t *stmts = Match(ast, Block)->statements;
- if (stmts && !stmts->next)
- return compile(env, stmts->ast);
+ if (stmts && !stmts->next) return compile(env, stmts->ast);
Text_t code = Text("({\n");
deferral_t *prev_deferred = env->deferred;
@@ -2996,7 +2931,8 @@ Text_t compile(env_t *env, ast_t *ast)
code = Texts(code, compile_statement(env, stmt->ast), "\n");
} else {
// TODO: put defer after evaluating block expression
- for (deferral_t *deferred = env->deferred; deferred && deferred != prev_deferred; deferred = deferred->next) {
+ for (deferral_t *deferred = env->deferred; deferred && deferred != prev_deferred;
+ deferred = deferred->next) {
code = Texts(code, compile_statement(deferred->defer_env, deferred->block));
}
code = Texts(code, compile(env, stmt->ast), ";\n");
@@ -3006,7 +2942,8 @@ Text_t compile(env_t *env, ast_t *ast)
return Texts(code, "})");
}
- case Min: case Max: {
+ case Min:
+ case Max: {
type_t *t = get_type(env, ast);
ast_t *key = ast->tag == Min ? Match(ast, Min)->key : Match(ast, Max)->key;
ast_t *lhs = ast->tag == Min ? Match(ast, Min)->lhs : Match(ast, Max)->lhs;
@@ -3024,23 +2961,23 @@ Text_t compile(env_t *env, ast_t *ast)
type_t *key_t = get_type(expr_env, key);
Text_t comparison;
if (key_t->tag == BigIntType)
- comparison = Texts("(Int$compare_value(", lhs_key, ", ", rhs_key, ")", (ast->tag == Min ? "<=" : ">="), "0)");
- else if (key_t->tag == IntType || key_t->tag == NumType || key_t->tag == BoolType || key_t->tag == PointerType || key_t->tag == ByteType)
+ comparison =
+ Texts("(Int$compare_value(", lhs_key, ", ", rhs_key, ")", (ast->tag == Min ? "<=" : ">="), "0)");
+ else if (key_t->tag == IntType || key_t->tag == NumType || key_t->tag == BoolType || key_t->tag == PointerType
+ || key_t->tag == ByteType)
comparison = Texts("((", lhs_key, ")", (ast->tag == Min ? "<=" : ">="), "(", rhs_key, "))");
else
- comparison = Texts("generic_compare(stack(", lhs_key, "), stack(", rhs_key, "), ", compile_type_info(key_t), ")",
- (ast->tag == Min ? "<=" : ">="), "0");
+ comparison = Texts("generic_compare(stack(", lhs_key, "), stack(", rhs_key, "), ", compile_type_info(key_t),
+ ")", (ast->tag == Min ? "<=" : ">="), "0");
- return Texts(
- "({\n",
- compile_type(t), " ternary$lhs = ", compile(env, lhs), ", ternary$rhs = ", compile(env, rhs), ";\n",
- comparison, " ? ternary$lhs : ternary$rhs;\n"
- "})");
+ return Texts("({\n", compile_type(t), " ternary$lhs = ", compile(env, lhs),
+ ", ternary$rhs = ", compile(env, rhs), ";\n", comparison,
+ " ? ternary$lhs : ternary$rhs;\n"
+ "})");
}
case List: {
DeclareMatch(list, ast, List);
- if (!list->items)
- return Text("(List_t){.length=0}");
+ if (!list->items) return Text("(List_t){.length=0}");
type_t *list_type = get_type(env, ast);
return compile_typed_list(env, ast, list_type);
@@ -3049,8 +2986,7 @@ Text_t compile(env_t *env, ast_t *ast)
DeclareMatch(table, ast, Table);
if (!table->entries) {
Text_t code = Text("((Table_t){");
- if (table->fallback)
- code = Texts(code, ".fallback=heap(", compile(env, table->fallback),")");
+ if (table->fallback) code = Texts(code, ".fallback=heap(", compile(env, table->fallback), ")");
return Texts(code, "})");
}
@@ -3059,8 +2995,7 @@ Text_t compile(env_t *env, ast_t *ast)
}
case Set: {
DeclareMatch(set, ast, Set);
- if (!set->items)
- return Text("((Table_t){})");
+ if (!set->items) return Text("((Table_t){})");
type_t *set_type = get_type(env, ast);
return compile_typed_set(env, ast, set_type);
@@ -3069,10 +3004,8 @@ Text_t compile(env_t *env, ast_t *ast)
ast_t *base = Match(ast, Comprehension)->expr;
while (base->tag == Comprehension)
base = Match(ast, Comprehension)->expr;
- if (base->tag == TableEntry)
- return compile(env, WrapAST(ast, Table, .entries=new(ast_list_t, .ast=ast)));
- else
- return compile(env, WrapAST(ast, List, .items=new(ast_list_t, .ast=ast)));
+ if (base->tag == TableEntry) return compile(env, WrapAST(ast, Table, .entries = new (ast_list_t, .ast = ast)));
+ else return compile(env, WrapAST(ast, List, .items = new (ast_list_t, .ast = ast)));
}
case Lambda: {
DeclareMatch(lambda, ast, Lambda);
@@ -3086,13 +3019,11 @@ Text_t compile(env_t *env, ast_t *ast)
}
type_t *ret_t = get_type(body_scope, lambda->body);
- if (ret_t->tag == ReturnType)
- ret_t = Match(ret_t, ReturnType)->ret;
+ if (ret_t->tag == ReturnType) ret_t = Match(ret_t, ReturnType)->ret;
if (lambda->ret_type) {
type_t *declared = parse_type_ast(env, lambda->ret_type);
- if (can_promote(ret_t, declared))
- ret_t = declared;
+ if (can_promote(ret_t, declared)) ret_t = declared;
else
code_err(ast, "This function was declared to return a value of type ", type_to_str(declared),
", but actually returns a value of type ", type_to_str(ret_t));
@@ -3104,12 +3035,15 @@ Text_t compile(env_t *env, ast_t *ast)
if (Table$length(closed_vars) > 0) { // Create a typedef for the lambda's closure userdata
Text_t def = Text("typedef struct {");
for (int64_t i = 0; i < closed_vars.entries.length; i++) {
- struct { const char *name; binding_t *b; } *entry = closed_vars.entries.data + closed_vars.entries.stride*i;
+ struct {
+ const char *name;
+ binding_t *b;
+ } *entry = closed_vars.entries.data + closed_vars.entries.stride * i;
if (has_stack_memory(entry->b->type))
code_err(ast, "This function is holding onto a reference to ", type_to_str(entry->b->type),
- " stack memory in the variable `", entry->name, "`, but the function may outlive the stack memory");
- if (entry->b->type->tag == ModuleType)
- continue;
+ " stack memory in the variable `", entry->name,
+ "`, but the function may outlive the stack memory");
+ if (entry->b->type->tag == ModuleType) continue;
set_binding(body_scope, entry->name, entry->b->type, Texts("userdata->", entry->name));
def = Texts(def, compile_declaration(entry->b->type, Text$from_str(entry->name)), "; ");
}
@@ -3130,18 +3064,18 @@ Text_t compile(env_t *env, ast_t *ast)
} else {
userdata = Texts("new(", name, "$userdata_t");
for (int64_t i = 0; i < closed_vars.entries.length; i++) {
- struct { const char *name; binding_t *b; } *entry = closed_vars.entries.data + closed_vars.entries.stride*i;
- if (entry->b->type->tag == ModuleType)
- continue;
+ struct {
+ const char *name;
+ binding_t *b;
+ } *entry = closed_vars.entries.data + closed_vars.entries.stride * i;
+ if (entry->b->type->tag == ModuleType) continue;
binding_t *b = get_binding(env, entry->name);
assert(b);
Text_t binding_code = b->code;
- if (entry->b->type->tag == ListType)
- userdata = Texts(userdata, ", LIST_COPY(", binding_code, ")");
+ if (entry->b->type->tag == ListType) userdata = Texts(userdata, ", LIST_COPY(", binding_code, ")");
else if (entry->b->type->tag == TableType || entry->b->type->tag == SetType)
userdata = Texts(userdata, ", TABLE_COPY(", binding_code, ")");
- else
- userdata = Texts(userdata, ", ", binding_code);
+ else userdata = Texts(userdata, ", ", binding_code);
}
userdata = Texts(userdata, ")");
code = Texts(code, name, "$userdata_t *userdata)");
@@ -3149,10 +3083,10 @@ Text_t compile(env_t *env, ast_t *ast)
Text_t body = EMPTY_TEXT;
for (ast_list_t *stmt = Match(lambda->body, Block)->statements; stmt; stmt = stmt->next) {
- if (stmt->next || ret_t->tag == VoidType || ret_t->tag == AbortType || get_type(body_scope, stmt->ast)->tag == ReturnType)
+ if (stmt->next || ret_t->tag == VoidType || ret_t->tag == AbortType
+ || get_type(body_scope, stmt->ast)->tag == ReturnType)
body = Texts(body, compile_statement(body_scope, stmt->ast), "\n");
- else
- body = Texts(body, compile_statement(body_scope, FakeAST(Return, stmt->ast)), "\n");
+ else body = Texts(body, compile_statement(body_scope, FakeAST(Return, stmt->ast)), "\n");
bind_statement(body_scope, stmt->ast);
}
if ((ret_t->tag == VoidType || ret_t->tag == AbortType) && body_scope->deferred)
@@ -3166,10 +3100,9 @@ Text_t compile(env_t *env, ast_t *ast)
type_t *self_t = get_type(env, call->self);
if (streq(call->name, "serialized")) {
- if (call->args)
- code_err(ast, ".serialized() doesn't take any arguments");
+ if (call->args) code_err(ast, ".serialized() doesn't take any arguments");
return Texts("generic_serialize((", compile_declaration(self_t, Text("[1]")), "){",
- compile(env, call->self), "}, ", compile_type_info(self_t), ")");
+ compile(env, call->self), "}, ", compile_type_info(self_t), ")");
}
int64_t pointer_depth = 0;
@@ -3178,23 +3111,29 @@ Text_t compile(env_t *env, ast_t *ast)
pointer_depth += 1;
if (self_value_t->tag == TypeInfoType || self_value_t->tag == ModuleType) {
- return compile(env, WrapAST(ast, FunctionCall, .fn=WrapAST(call->self, FieldAccess, .fielded=call->self, .field=call->name),
- .args=call->args));
+ return compile(env,
+ WrapAST(ast, FunctionCall,
+ .fn = WrapAST(call->self, FieldAccess, .fielded = call->self, .field = call->name),
+ .args = call->args));
}
type_t *field_type = get_field_type(self_value_t, call->name);
- if (field_type && field_type->tag == ClosureType)
- field_type = Match(field_type, ClosureType)->fn;
+ if (field_type && field_type->tag == ClosureType) field_type = Match(field_type, ClosureType)->fn;
if (field_type && field_type->tag == FunctionType)
- return compile(env, WrapAST(ast, FunctionCall, .fn=WrapAST(call->self, FieldAccess, .fielded=call->self, .field=call->name),
- .args=call->args));
+ return compile(env,
+ WrapAST(ast, FunctionCall,
+ .fn = WrapAST(call->self, FieldAccess, .fielded = call->self, .field = call->name),
+ .args = call->args));
Text_t self = compile(env, call->self);
-#define EXPECT_POINTER(article, name) do { \
- if (pointer_depth < 1) code_err(call->self, "I expected "article" "name" pointer here, not "article" "name" value"); \
- else if (pointer_depth > 1) code_err(call->self, "I expected "article" "name" pointer here, not a nested "name" pointer"); \
-} while (0)
+#define EXPECT_POINTER(article, name) \
+ do { \
+ if (pointer_depth < 1) \
+ code_err(call->self, "I expected " article " " name " pointer here, not " article " " name " value"); \
+ else if (pointer_depth > 1) \
+ code_err(call->self, "I expected " article " " name " pointer here, not a nested " name " pointer"); \
+ } while (0)
switch (self_value_t->tag) {
case ListType: {
type_t *item_t = Match(self_value_t, ListType)->item_type;
@@ -3202,116 +3141,141 @@ Text_t compile(env_t *env, ast_t *ast)
if (streq(call->name, "insert")) {
EXPECT_POINTER("a", "list");
- arg_t *arg_spec = new(arg_t, .name="item", .type=item_t,
- .next=new(arg_t, .name="at", .type=INT_TYPE, .default_val=FakeAST(Int, .str="0")));
+ arg_t *arg_spec =
+ new (arg_t, .name = "item", .type = item_t,
+ .next = new (arg_t, .name = "at", .type = INT_TYPE, .default_val = FakeAST(Int, .str = "0")));
return Texts("List$insert_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- padded_item_size, ")");
+ padded_item_size, ")");
} else if (streq(call->name, "insert_all")) {
EXPECT_POINTER("a", "list");
- arg_t *arg_spec = new(arg_t, .name="items", .type=self_value_t,
- .next=new(arg_t, .name="at", .type=INT_TYPE, .default_val=FakeAST(Int, .str="0")));
+ arg_t *arg_spec =
+ new (arg_t, .name = "items", .type = self_value_t,
+ .next = new (arg_t, .name = "at", .type = INT_TYPE, .default_val = FakeAST(Int, .str = "0")));
return Texts("List$insert_all(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- padded_item_size, ")");
+ padded_item_size, ")");
} else if (streq(call->name, "remove_at")) {
EXPECT_POINTER("a", "list");
- arg_t *arg_spec = new(arg_t, .name="index", .type=INT_TYPE, .default_val=FakeAST(Int, .str="-1"),
- .next=new(arg_t, .name="count", .type=INT_TYPE, .default_val=FakeAST(Int, .str="1")));
+ arg_t *arg_spec = new (
+ arg_t, .name = "index", .type = INT_TYPE, .default_val = FakeAST(Int, .str = "-1"),
+ .next = new (arg_t, .name = "count", .type = INT_TYPE, .default_val = FakeAST(Int, .str = "1")));
return Texts("List$remove_at(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- padded_item_size, ")");
+ padded_item_size, ")");
} else if (streq(call->name, "remove_item")) {
EXPECT_POINTER("a", "list");
- arg_t *arg_spec = new(arg_t, .name="item", .type=item_t,
- .next=new(arg_t, .name="max_count", .type=INT_TYPE, .default_val=FakeAST(Int, .str="-1")));
- return Texts("List$remove_item_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- compile_type_info(self_value_t), ")");
+ arg_t *arg_spec = new (arg_t, .name = "item", .type = item_t,
+ .next = new (arg_t, .name = "max_count", .type = INT_TYPE,
+ .default_val = FakeAST(Int, .str = "-1")));
+ return Texts("List$remove_item_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args),
+ ", ", compile_type_info(self_value_t), ")");
} else if (streq(call->name, "has")) {
self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new(arg_t, .name="item", .type=item_t);
+ arg_t *arg_spec = new (arg_t, .name = "item", .type = item_t);
return Texts("List$has_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- compile_type_info(self_value_t), ")");
+ compile_type_info(self_value_t), ")");
} else if (streq(call->name, "sample")) {
type_t *random_num_type = parse_type_string(env, "func(->Num)?");
self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new(arg_t, .name="count", .type=INT_TYPE,
- .next=new(arg_t, .name="weights", .type=Type(ListType, .item_type=Type(NumType, .bits=TYPE_NBITS64)),
- .default_val=FakeAST(None),
- .next=new(arg_t, .name="random", .type=random_num_type, .default_val=FakeAST(None))));
+ arg_t *arg_spec =
+ new (arg_t, .name = "count", .type = INT_TYPE,
+ .next = new (arg_t, .name = "weights",
+ .type = Type(ListType, .item_type = Type(NumType, .bits = TYPE_NBITS64)),
+ .default_val = FakeAST(None),
+ .next = new (arg_t, .name = "random", .type = random_num_type,
+ .default_val = FakeAST(None))));
return Texts("List$sample(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- padded_item_size, ")");
+ padded_item_size, ")");
} else if (streq(call->name, "shuffle")) {
type_t *random_int64_type = parse_type_string(env, "func(min,max:Int64->Int64)?");
EXPECT_POINTER("a", "list");
- arg_t *arg_spec = new(arg_t, .name="random", .type=random_int64_type, .default_val=FakeAST(None));
- return Texts("List$shuffle(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", padded_item_size, ")");
+ arg_t *arg_spec =
+ new (arg_t, .name = "random", .type = random_int64_type, .default_val = FakeAST(None));
+ return Texts("List$shuffle(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
+ padded_item_size, ")");
} else if (streq(call->name, "shuffled")) {
type_t *random_int64_type = parse_type_string(env, "func(min,max:Int64->Int64)?");
self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new(arg_t, .name="random", .type=random_int64_type, .default_val=FakeAST(None));
- return Texts("List$shuffled(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", padded_item_size, ")");
+ arg_t *arg_spec =
+ new (arg_t, .name = "random", .type = random_int64_type, .default_val = FakeAST(None));
+ return Texts("List$shuffled(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
+ padded_item_size, ")");
} else if (streq(call->name, "random")) {
type_t *random_int64_type = parse_type_string(env, "func(min,max:Int64->Int64)?");
self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new(arg_t, .name="random", .type=random_int64_type, .default_val=FakeAST(None));
- return Texts("List$random_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", compile_type(item_t), ")");
+ arg_t *arg_spec =
+ new (arg_t, .name = "random", .type = random_int64_type, .default_val = FakeAST(None));
+ return Texts("List$random_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
+ compile_type(item_t), ")");
} else if (streq(call->name, "sort") || streq(call->name, "sorted")) {
- if (streq(call->name, "sort"))
- EXPECT_POINTER("a", "list");
- else
- self = compile_to_pointer_depth(env, call->self, 0, false);
+ if (streq(call->name, "sort")) EXPECT_POINTER("a", "list");
+ else self = compile_to_pointer_depth(env, call->self, 0, false);
Text_t comparison;
if (call->args) {
- type_t *item_ptr = Type(PointerType, .pointed=item_t, .is_stack=true);
- type_t *fn_t = NewFunctionType(Type(IntType, .bits=TYPE_IBITS32), {.name="x", .type=item_ptr}, {.name="y", .type=item_ptr});
- arg_t *arg_spec = new(arg_t, .name="by", .type=Type(ClosureType, .fn=fn_t));
+ type_t *item_ptr = Type(PointerType, .pointed = item_t, .is_stack = true);
+ type_t *fn_t = NewFunctionType(Type(IntType, .bits = TYPE_IBITS32), {.name = "x", .type = item_ptr},
+ {.name = "y", .type = item_ptr});
+ arg_t *arg_spec = new (arg_t, .name = "by", .type = Type(ClosureType, .fn = fn_t));
comparison = compile_arguments(env, ast, arg_spec, call->args);
} else {
- comparison = Texts("((Closure_t){.fn=generic_compare, .userdata=(void*)", compile_type_info(item_t), "})");
+ comparison = Texts("((Closure_t){.fn=generic_compare, "
+ ".userdata=(void*)",
+ compile_type_info(item_t), "})");
}
return Texts("List$", call->name, "(", self, ", ", comparison, ", ", padded_item_size, ")");
} else if (streq(call->name, "heapify")) {
EXPECT_POINTER("a", "list");
Text_t comparison;
if (call->args) {
- type_t *item_ptr = Type(PointerType, .pointed=item_t, .is_stack=true);
- type_t *fn_t = NewFunctionType(Type(IntType, .bits=TYPE_IBITS32), {.name="x", .type=item_ptr}, {.name="y", .type=item_ptr});
- arg_t *arg_spec = new(arg_t, .name="by", .type=Type(ClosureType, .fn=fn_t));
+ type_t *item_ptr = Type(PointerType, .pointed = item_t, .is_stack = true);
+ type_t *fn_t = NewFunctionType(Type(IntType, .bits = TYPE_IBITS32), {.name = "x", .type = item_ptr},
+ {.name = "y", .type = item_ptr});
+ arg_t *arg_spec = new (arg_t, .name = "by", .type = Type(ClosureType, .fn = fn_t));
comparison = compile_arguments(env, ast, arg_spec, call->args);
} else {
- comparison = Texts("((Closure_t){.fn=generic_compare, .userdata=(void*)", compile_type_info(item_t), "})");
+ comparison = Texts("((Closure_t){.fn=generic_compare, "
+ ".userdata=(void*)",
+ compile_type_info(item_t), "})");
}
return Texts("List$heapify(", self, ", ", comparison, ", ", padded_item_size, ")");
} else if (streq(call->name, "heap_push")) {
EXPECT_POINTER("a", "list");
- type_t *item_ptr = Type(PointerType, .pointed=item_t, .is_stack=true);
- type_t *fn_t = NewFunctionType(Type(IntType, .bits=TYPE_IBITS32), {.name="x", .type=item_ptr}, {.name="y", .type=item_ptr});
- ast_t *default_cmp = LiteralCode(Texts("((Closure_t){.fn=generic_compare, .userdata=(void*)",
- compile_type_info(item_t), "})"),
- .type=Type(ClosureType, .fn=fn_t));
- arg_t *arg_spec = new(arg_t, .name="item", .type=item_t,
- .next=new(arg_t, .name="by", .type=Type(ClosureType, .fn=fn_t), .default_val=default_cmp));
+ type_t *item_ptr = Type(PointerType, .pointed = item_t, .is_stack = true);
+ type_t *fn_t = NewFunctionType(Type(IntType, .bits = TYPE_IBITS32), {.name = "x", .type = item_ptr},
+ {.name = "y", .type = item_ptr});
+ ast_t *default_cmp = LiteralCode(Texts("((Closure_t){.fn=generic_compare, "
+ ".userdata=(void*)",
+ compile_type_info(item_t), "})"),
+ .type = Type(ClosureType, .fn = fn_t));
+ arg_t *arg_spec = new (arg_t, .name = "item", .type = item_t,
+ .next = new (arg_t, .name = "by", .type = Type(ClosureType, .fn = fn_t),
+ .default_val = default_cmp));
Text_t arg_code = compile_arguments(env, ast, arg_spec, call->args);
return Texts("List$heap_push_value(", self, ", ", arg_code, ", ", padded_item_size, ")");
} else if (streq(call->name, "heap_pop")) {
EXPECT_POINTER("a", "list");
- type_t *item_ptr = Type(PointerType, .pointed=item_t, .is_stack=true);
- type_t *fn_t = NewFunctionType(Type(IntType, .bits=TYPE_IBITS32), {.name="x", .type=item_ptr}, {.name="y", .type=item_ptr});
- ast_t *default_cmp = LiteralCode(Texts("((Closure_t){.fn=generic_compare, .userdata=(void*)",
- compile_type_info(item_t), "})"),
- .type=Type(ClosureType, .fn=fn_t));
- arg_t *arg_spec = new(arg_t, .name="by", .type=Type(ClosureType, .fn=fn_t), .default_val=default_cmp);
+ type_t *item_ptr = Type(PointerType, .pointed = item_t, .is_stack = true);
+ type_t *fn_t = NewFunctionType(Type(IntType, .bits = TYPE_IBITS32), {.name = "x", .type = item_ptr},
+ {.name = "y", .type = item_ptr});
+ ast_t *default_cmp = LiteralCode(Texts("((Closure_t){.fn=generic_compare, "
+ ".userdata=(void*)",
+ compile_type_info(item_t), "})"),
+ .type = Type(ClosureType, .fn = fn_t));
+ arg_t *arg_spec =
+ new (arg_t, .name = "by", .type = Type(ClosureType, .fn = fn_t), .default_val = default_cmp);
Text_t arg_code = compile_arguments(env, ast, arg_spec, call->args);
return Texts("List$heap_pop_value(", self, ", ", arg_code, ", ", compile_type(item_t), ", _, ",
- promote_to_optional(item_t, Text("_")), ", ", compile_none(item_t), ")");
+ promote_to_optional(item_t, Text("_")), ", ", compile_none(item_t), ")");
} else if (streq(call->name, "binary_search")) {
self = compile_to_pointer_depth(env, call->self, 0, call->args != NULL);
- type_t *item_ptr = Type(PointerType, .pointed=item_t, .is_stack=true);
- type_t *fn_t = NewFunctionType(Type(IntType, .bits=TYPE_IBITS32), {.name="x", .type=item_ptr}, {.name="y", .type=item_ptr});
- ast_t *default_cmp = LiteralCode(
- Texts("((Closure_t){.fn=generic_compare, .userdata=(void*)",
- compile_type_info(item_t), "})"),
- .type=Type(ClosureType, .fn=fn_t));
- arg_t *arg_spec = new(arg_t, .name="target", .type=item_t,
- .next=new(arg_t, .name="by", .type=Type(ClosureType, .fn=fn_t), .default_val=default_cmp));
+ type_t *item_ptr = Type(PointerType, .pointed = item_t, .is_stack = true);
+ type_t *fn_t = NewFunctionType(Type(IntType, .bits = TYPE_IBITS32), {.name = "x", .type = item_ptr},
+ {.name = "y", .type = item_ptr});
+ ast_t *default_cmp = LiteralCode(Texts("((Closure_t){.fn=generic_compare, "
+ ".userdata=(void*)",
+ compile_type_info(item_t), "})"),
+ .type = Type(ClosureType, .fn = fn_t));
+ arg_t *arg_spec = new (arg_t, .name = "target", .type = item_t,
+ .next = new (arg_t, .name = "by", .type = Type(ClosureType, .fn = fn_t),
+ .default_val = default_cmp));
Text_t arg_code = compile_arguments(env, ast, arg_spec, call->args);
return Texts("List$binary_search_value(", self, ", ", arg_code, ")");
} else if (streq(call->name, "clear")) {
@@ -3320,32 +3284,34 @@ Text_t compile(env_t *env, ast_t *ast)
return Texts("List$clear(", self, ")");
} else if (streq(call->name, "find")) {
self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new(arg_t, .name="item", .type=item_t);
- return Texts("List$find_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args),
- ", ", compile_type_info(self_value_t), ")");
+ arg_t *arg_spec = new (arg_t, .name = "item", .type = item_t);
+ return Texts("List$find_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
+ compile_type_info(self_value_t), ")");
} else if (streq(call->name, "where")) {
self = compile_to_pointer_depth(env, call->self, 0, call->args != NULL);
- type_t *item_ptr = Type(PointerType, .pointed=item_t, .is_stack=true);
- type_t *predicate_type = Type(
- ClosureType, .fn=NewFunctionType(Type(BoolType), {.name="item", .type=item_ptr}));
- arg_t *arg_spec = new(arg_t, .name="predicate", .type=predicate_type);
+ type_t *item_ptr = Type(PointerType, .pointed = item_t, .is_stack = true);
+ type_t *predicate_type =
+ Type(ClosureType, .fn = NewFunctionType(Type(BoolType), {.name = "item", .type = item_ptr}));
+ arg_t *arg_spec = new (arg_t, .name = "predicate", .type = predicate_type);
return Texts("List$first(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ")");
} else if (streq(call->name, "from")) {
self = compile_to_pointer_depth(env, call->self, 0, true);
- arg_t *arg_spec = new(arg_t, .name="first", .type=INT_TYPE);
+ arg_t *arg_spec = new (arg_t, .name = "first", .type = INT_TYPE);
return Texts("List$from(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ")");
} else if (streq(call->name, "to")) {
self = compile_to_pointer_depth(env, call->self, 0, true);
- arg_t *arg_spec = new(arg_t, .name="last", .type=INT_TYPE);
+ arg_t *arg_spec = new (arg_t, .name = "last", .type = INT_TYPE);
return Texts("List$to(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ")");
} else if (streq(call->name, "slice")) {
self = compile_to_pointer_depth(env, call->self, 0, true);
- arg_t *arg_spec = new(arg_t, .name="first", .type=INT_TYPE, .next=new(arg_t, .name="last", .type=INT_TYPE));
+ arg_t *arg_spec = new (arg_t, .name = "first", .type = INT_TYPE,
+ .next = new (arg_t, .name = "last", .type = INT_TYPE));
return Texts("List$slice(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ")");
} else if (streq(call->name, "by")) {
self = compile_to_pointer_depth(env, call->self, 0, true);
- arg_t *arg_spec = new(arg_t, .name="stride", .type=INT_TYPE);
- return Texts("List$by(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ", padded_item_size, ")");
+ arg_t *arg_spec = new (arg_t, .name = "stride", .type = INT_TYPE);
+ return Texts("List$by(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
+ padded_item_size, ")");
} else if (streq(call->name, "reversed")) {
self = compile_to_pointer_depth(env, call->self, 0, true);
(void)compile_arguments(env, ast, NULL, call->args);
@@ -3356,7 +3322,7 @@ Text_t compile(env_t *env, ast_t *ast)
return Texts("Table$from_entries(", self, ", Set$info(", compile_type_info(item_t), "))");
} else if (streq(call->name, "pop")) {
EXPECT_POINTER("a", "list");
- arg_t *arg_spec = new(arg_t, .name="index", .type=INT_TYPE, .default_val=FakeAST(Int, "-1"));
+ arg_t *arg_spec = new (arg_t, .name = "index", .type = INT_TYPE, .default_val = FakeAST(Int, "-1"));
Text_t index = compile_arguments(env, ast, arg_spec, call->args);
return Texts("List$pop(", self, ", ", index, ", ", compile_type(item_t), ", _, ",
promote_to_optional(item_t, Text("_")), ", ", compile_none(item_t), ")");
@@ -3370,103 +3336,105 @@ Text_t compile(env_t *env, ast_t *ast)
DeclareMatch(set, self_value_t, SetType);
if (streq(call->name, "has")) {
self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new(arg_t, .name="key", .type=set->item_type);
+ arg_t *arg_spec = new (arg_t, .name = "key", .type = set->item_type);
return Texts("Table$has_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- compile_type_info(self_value_t), ")");
+ compile_type_info(self_value_t), ")");
} else if (streq(call->name, "add")) {
EXPECT_POINTER("a", "set");
- arg_t *arg_spec = new(arg_t, .name="item", .type=set->item_type);
- return Texts("Table$set_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", NULL, ",
- compile_type_info(self_value_t), ")");
+ arg_t *arg_spec = new (arg_t, .name = "item", .type = set->item_type);
+ return Texts("Table$set_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args),
+ ", NULL, ", compile_type_info(self_value_t), ")");
} else if (streq(call->name, "add_all")) {
EXPECT_POINTER("a", "set");
- arg_t *arg_spec = new(arg_t, .name="items", .type=Type(ListType, .item_type=Match(self_value_t, SetType)->item_type));
+ arg_t *arg_spec = new (arg_t, .name = "items",
+ .type = Type(ListType, .item_type = Match(self_value_t, SetType)->item_type));
return Texts("({ Table_t *set = ", self, "; ",
- "List_t to_add = ", compile_arguments(env, ast, arg_spec, call->args), "; ",
- "for (int64_t i = 0; i < to_add.length; i++)\n"
- "Table$set(set, to_add.data + i*to_add.stride, NULL, ", compile_type_info(self_value_t), ");\n",
- "(void)0; })");
+ "List_t to_add = ", compile_arguments(env, ast, arg_spec, call->args), "; ",
+ "for (int64_t i = 0; i < to_add.length; i++)\n"
+ "Table$set(set, to_add.data + i*to_add.stride, NULL, ",
+ compile_type_info(self_value_t), ");\n", "(void)0; })");
} else if (streq(call->name, "remove")) {
EXPECT_POINTER("a", "set");
- arg_t *arg_spec = new(arg_t, .name="item", .type=set->item_type);
+ arg_t *arg_spec = new (arg_t, .name = "item", .type = set->item_type);
return Texts("Table$remove_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- compile_type_info(self_value_t), ")");
+ compile_type_info(self_value_t), ")");
} else if (streq(call->name, "remove_all")) {
EXPECT_POINTER("a", "set");
- arg_t *arg_spec = new(arg_t, .name="items", .type=Type(ListType, .item_type=Match(self_value_t, SetType)->item_type));
+ arg_t *arg_spec = new (arg_t, .name = "items",
+ .type = Type(ListType, .item_type = Match(self_value_t, SetType)->item_type));
return Texts("({ Table_t *set = ", self, "; ",
- "List_t to_add = ", compile_arguments(env, ast, arg_spec, call->args), "; ",
- "for (int64_t i = 0; i < to_add.length; i++)\n"
- "Table$remove(set, to_add.data + i*to_add.stride, ", compile_type_info(self_value_t), ");\n",
- "(void)0; })");
+ "List_t to_add = ", compile_arguments(env, ast, arg_spec, call->args), "; ",
+ "for (int64_t i = 0; i < to_add.length; i++)\n"
+ "Table$remove(set, to_add.data + i*to_add.stride, ",
+ compile_type_info(self_value_t), ");\n", "(void)0; })");
} else if (streq(call->name, "clear")) {
EXPECT_POINTER("a", "set");
(void)compile_arguments(env, ast, NULL, call->args);
return Texts("Table$clear(", self, ")");
} else if (streq(call->name, "with")) {
self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new(arg_t, .name="other", .type=self_value_t);
- return Texts("Table$with(", self, ", ", compile_arguments(env, ast, arg_spec, call->args),
- ", ", compile_type_info(self_value_t), ")");
+ arg_t *arg_spec = new (arg_t, .name = "other", .type = self_value_t);
+ return Texts("Table$with(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
+ compile_type_info(self_value_t), ")");
} else if (streq(call->name, "overlap")) {
self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new(arg_t, .name="other", .type=self_value_t);
- return Texts("Table$overlap(", self, ", ", compile_arguments(env, ast, arg_spec, call->args),
- ", ", compile_type_info(self_value_t), ")");
+ arg_t *arg_spec = new (arg_t, .name = "other", .type = self_value_t);
+ return Texts("Table$overlap(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
+ compile_type_info(self_value_t), ")");
} else if (streq(call->name, "without")) {
self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new(arg_t, .name="other", .type=self_value_t);
- return Texts("Table$without(", self, ", ", compile_arguments(env, ast, arg_spec, call->args),
- ", ", compile_type_info(self_value_t), ")");
+ arg_t *arg_spec = new (arg_t, .name = "other", .type = self_value_t);
+ return Texts("Table$without(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
+ compile_type_info(self_value_t), ")");
} else if (streq(call->name, "is_subset_of")) {
self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new(arg_t, .name="other", .type=self_value_t,
- .next=new(arg_t, .name="strict", .type=Type(BoolType), .default_val=FakeAST(Bool, false)));
- return Texts("Table$is_subset_of(", self, ", ", compile_arguments(env, ast, arg_spec, call->args),
- ", ", compile_type_info(self_value_t), ")");
+ arg_t *arg_spec = new (
+ arg_t, .name = "other", .type = self_value_t,
+ .next = new (arg_t, .name = "strict", .type = Type(BoolType), .default_val = FakeAST(Bool, false)));
+ return Texts("Table$is_subset_of(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
+ compile_type_info(self_value_t), ")");
} else if (streq(call->name, "is_superset_of")) {
self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new(arg_t, .name="other", .type=self_value_t,
- .next=new(arg_t, .name="strict", .type=Type(BoolType), .default_val=FakeAST(Bool, false)));
+ arg_t *arg_spec = new (
+ arg_t, .name = "other", .type = self_value_t,
+ .next = new (arg_t, .name = "strict", .type = Type(BoolType), .default_val = FakeAST(Bool, false)));
return Texts("Table$is_superset_of(", self, ", ", compile_arguments(env, ast, arg_spec, call->args),
- ", ", compile_type_info(self_value_t), ")");
+ ", ", compile_type_info(self_value_t), ")");
} else code_err(ast, "There is no '", call->name, "' method for tables");
}
case TableType: {
DeclareMatch(table, self_value_t, TableType);
if (streq(call->name, "get")) {
self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new(arg_t, .name="key", .type=table->key_type);
- return Texts(
- "Table$get_optional(", self, ", ", compile_type(table->key_type), ", ",
- compile_type(table->value_type), ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- "_, ", optional_into_nonnone(table->value_type, Text("(*_)")), ", ", compile_none(table->value_type), ", ",
- compile_type_info(self_value_t), ")");
+ arg_t *arg_spec = new (arg_t, .name = "key", .type = table->key_type);
+ return Texts("Table$get_optional(", self, ", ", compile_type(table->key_type), ", ",
+ compile_type(table->value_type), ", ", compile_arguments(env, ast, arg_spec, call->args),
+ ", ", "_, ", optional_into_nonnone(table->value_type, Text("(*_)")), ", ",
+ compile_none(table->value_type), ", ", compile_type_info(self_value_t), ")");
} else if (streq(call->name, "get_or_set")) {
self = compile_to_pointer_depth(env, call->self, 1, false);
- arg_t *arg_spec = new(arg_t, .name="key", .type=table->key_type,
- .next=new(arg_t, .name="default", .type=table->value_type, .default_val=table->default_value));
- return Texts("*Table$get_or_setdefault(",
- self, ", ", compile_type(table->key_type), ", ",
- compile_type(table->value_type), ", ",
- compile_arguments(env, ast, arg_spec, call->args), ", ",
- compile_type_info(self_value_t), ")");
+ arg_t *arg_spec = new (arg_t, .name = "key", .type = table->key_type,
+ .next = new (arg_t, .name = "default", .type = table->value_type,
+ .default_val = table->default_value));
+ return Texts("*Table$get_or_setdefault(", self, ", ", compile_type(table->key_type), ", ",
+ compile_type(table->value_type), ", ", compile_arguments(env, ast, arg_spec, call->args),
+ ", ", compile_type_info(self_value_t), ")");
} else if (streq(call->name, "has")) {
self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new(arg_t, .name="key", .type=table->key_type);
+ arg_t *arg_spec = new (arg_t, .name = "key", .type = table->key_type);
return Texts("Table$has_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- compile_type_info(self_value_t), ")");
+ compile_type_info(self_value_t), ")");
} else if (streq(call->name, "set")) {
EXPECT_POINTER("a", "table");
- arg_t *arg_spec = new(arg_t, .name="key", .type=table->key_type,
- .next=new(arg_t, .name="value", .type=table->value_type));
+ arg_t *arg_spec = new (arg_t, .name = "key", .type = table->key_type,
+ .next = new (arg_t, .name = "value", .type = table->value_type));
return Texts("Table$set_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- compile_type_info(self_value_t), ")");
+ compile_type_info(self_value_t), ")");
} else if (streq(call->name, "remove")) {
EXPECT_POINTER("a", "table");
- arg_t *arg_spec = new(arg_t, .name="key", .type=table->key_type);
+ arg_t *arg_spec = new (arg_t, .name = "key", .type = table->key_type);
return Texts("Table$remove_value(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ", ",
- compile_type_info(self_value_t), ")");
+ compile_type_info(self_value_t), ")");
} else if (streq(call->name, "clear")) {
EXPECT_POINTER("a", "table");
(void)compile_arguments(env, ast, NULL, call->args);
@@ -3477,14 +3445,15 @@ Text_t compile(env_t *env, ast_t *ast)
return Texts("Table$sorted(", self, ", ", compile_type_info(self_value_t), ")");
} else if (streq(call->name, "with_fallback")) {
self = compile_to_pointer_depth(env, call->self, 0, false);
- arg_t *arg_spec = new(arg_t, .name="fallback", .type=Type(OptionalType, self_value_t));
- return Texts("Table$with_fallback(", self, ", ", compile_arguments(env, ast, arg_spec, call->args), ")");
+ arg_t *arg_spec = new (arg_t, .name = "fallback", .type = Type(OptionalType, self_value_t));
+ return Texts("Table$with_fallback(", self, ", ", compile_arguments(env, ast, arg_spec, call->args),
+ ")");
} else code_err(ast, "There is no '", call->name, "' method for tables");
}
default: {
DeclareMatch(methodcall, ast, MethodCall);
type_t *fn_t = get_method_type(env, methodcall->self, methodcall->name);
- arg_ast_t *args = new(arg_ast_t, .value=methodcall->self, .next=methodcall->args);
+ arg_ast_t *args = new (arg_ast_t, .value = methodcall->self, .next = methodcall->args);
binding_t *b = get_namespace_binding(env, methodcall->self, methodcall->name);
if (!b) code_err(ast, "No such method");
return Texts(b->code, "(", compile_arguments(env, ast, Match(fn_t, FunctionType)->args, args), ")");
@@ -3501,14 +3470,15 @@ Text_t compile(env_t *env, ast_t *ast)
} else if (fn_t->tag == TypeInfoType) {
type_t *t = Match(fn_t, TypeInfoType)->type;
- // Literal constructors for numeric types like `Byte(123)` should not go through any conversion, just a cast:
+ // Literal constructors for numeric types like `Byte(123)` should
+ // not go through any conversion, just a cast:
if (is_numeric_type(t) && call->args && !call->args->next && call->args->value->tag == Int)
return compile_to_type(env, call->args->value, t);
else if (t->tag == NumType && call->args && !call->args->next && call->args->value->tag == Num)
return compile_to_type(env, call->args->value, t);
- binding_t *constructor = get_constructor(env, t, call->args,
- env->current_type != NULL && type_eq(env->current_type, t));
+ binding_t *constructor =
+ get_constructor(env, t, call->args, env->current_type != NULL && type_eq(env->current_type, t));
if (constructor) {
arg_t *arg_spec = Match(constructor->type, FunctionType)->args;
return Texts(constructor->code, "(", compile_arguments(env, ast, arg_spec, call->args), ")");
@@ -3518,49 +3488,61 @@ Text_t compile(env_t *env, ast_t *ast)
if (t->tag == TextType) {
if (!call->args) code_err(ast, "This constructor needs a value");
if (!type_eq(t, TEXT_TYPE))
- code_err(call->fn, "I don't have a constructor defined for these arguments");
+ code_err(call->fn, "I don't have a constructor defined for "
+ "these arguments");
// Text constructor:
- if (!call->args || call->args->next)
- code_err(call->fn, "This constructor takes exactly 1 argument");
- if (type_eq(actual, t))
- return compile(env, call->args->value);
+ if (!call->args || call->args->next) code_err(call->fn, "This constructor takes exactly 1 argument");
+ if (type_eq(actual, t)) return compile(env, call->args->value);
return expr_as_text(compile(env, call->args->value), actual, Text("no"));
} else if (t->tag == CStringType) {
// C String constructor:
- if (!call->args || call->args->next)
- code_err(call->fn, "This constructor takes exactly 1 argument");
+ if (!call->args || call->args->next) code_err(call->fn, "This constructor takes exactly 1 argument");
if (call->args->value->tag == TextLiteral)
return compile_text_literal(Match(call->args->value, TextLiteral)->text);
else if (call->args->value->tag == TextJoin && Match(call->args->value, TextJoin)->children == NULL)
return Text("\"\"");
- else if (call->args->value->tag == TextJoin && Match(call->args->value, TextJoin)->children->next == NULL)
- return compile_text_literal(Match(Match(call->args->value, TextJoin)->children->ast, TextLiteral)->text);
- return Texts("Text$as_c_string(", expr_as_text(compile(env, call->args->value), actual, Text("no")), ")");
+ else if (call->args->value->tag == TextJoin
+ && Match(call->args->value, TextJoin)->children->next == NULL)
+ return compile_text_literal(
+ Match(Match(call->args->value, TextJoin)->children->ast, TextLiteral)->text);
+ return Texts("Text$as_c_string(", expr_as_text(compile(env, call->args->value), actual, Text("no")),
+ ")");
} else if (t->tag == StructType) {
DeclareMatch(struct_, t, StructType);
if (!struct_->opaque && is_valid_call(env, struct_->fields, call->args, true)) {
if (env->current_type == NULL || !type_eq(env->current_type, t)) {
for (arg_t *field = struct_->fields; field; field = field->next) {
if (field->name[0] == '_')
- code_err(ast, "This struct can't be initialized directly because it has private fields (starting with underscore).\n"
- "Use a `convert` or `func` to instantiate the type instead.");
+ code_err(ast, "This struct can't be "
+ "initialized directly because it "
+ "has private fields (starting "
+ "with underscore).\n"
+ "Use a `convert` or `func` to "
+ "instantiate the type "
+ "instead.");
}
}
- return Texts("((", compile_type(t), "){",
- compile_arguments(env, ast, struct_->fields, call->args), "})");
+ return Texts("((", compile_type(t), "){", compile_arguments(env, ast, struct_->fields, call->args),
+ "})");
}
}
- code_err(ast, "I could not find a constructor matching these arguments for ", type_to_str(t));
+ code_err(ast,
+ "I could not find a constructor matching these arguments "
+ "for ",
+ type_to_str(t));
} else if (fn_t->tag == ClosureType) {
fn_t = Match(fn_t, ClosureType)->fn;
arg_t *type_args = Match(fn_t, FunctionType)->args;
arg_t *closure_fn_args = NULL;
for (arg_t *arg = Match(fn_t, FunctionType)->args; arg; arg = arg->next)
- closure_fn_args = new(arg_t, .name=arg->name, .type=arg->type, .default_val=arg->default_val, .next=closure_fn_args);
- closure_fn_args = new(arg_t, .name="userdata", .type=Type(PointerType, .pointed=Type(MemoryType)), .next=closure_fn_args);
+ closure_fn_args = new (arg_t, .name = arg->name, .type = arg->type, .default_val = arg->default_val,
+ .next = closure_fn_args);
+ closure_fn_args = new (arg_t, .name = "userdata", .type = Type(PointerType, .pointed = Type(MemoryType)),
+ .next = closure_fn_args);
REVERSE_LIST(closure_fn_args);
- Text_t fn_type_code = compile_type(Type(FunctionType, .args=closure_fn_args, .ret=Match(fn_t, FunctionType)->ret));
+ Text_t fn_type_code =
+ compile_type(Type(FunctionType, .args = closure_fn_args, .ret = Match(fn_t, FunctionType)->ret));
Text_t closure = compile(env, call->fn);
Text_t arg_code = compile_arguments(env, ast, type_args, call->args);
@@ -3568,8 +3550,8 @@ Text_t compile(env_t *env, ast_t *ast)
if (call->fn->tag == Var) {
return Texts("((", fn_type_code, ")", closure, ".fn)(", arg_code, closure, ".userdata)");
} else {
- return Texts("({ Closure_t closure = ", closure, "; ((", fn_type_code, ")closure.fn)(",
- arg_code, "closure.userdata); })");
+ return Texts("({ Closure_t closure = ", closure, "; ((", fn_type_code, ")closure.fn)(", arg_code,
+ "closure.userdata); })");
}
} else {
code_err(call->fn, "This is not a function, it's a ", type_to_str(fn_t));
@@ -3581,27 +3563,30 @@ Text_t compile(env_t *env, ast_t *ast)
if (!type_eq(value_type, Type(ListType, Type(ByteType))))
code_err(value, "This value should be a list of bytes, not a ", type_to_str(value_type));
type_t *t = parse_type_ast(env, Match(ast, Deserialize)->type);
- return Texts("({ ", compile_declaration(t, Text("deserialized")), ";\n"
- "generic_deserialize(", compile(env, value), ", &deserialized, ", compile_type_info(t), ");\n"
- "deserialized; })");
+ return Texts("({ ", compile_declaration(t, Text("deserialized")),
+ ";\n"
+ "generic_deserialize(",
+ compile(env, value), ", &deserialized, ", compile_type_info(t),
+ ");\n"
+ "deserialized; })");
}
case ExplicitlyTyped: {
return compile_to_type(env, Match(ast, ExplicitlyTyped)->ast, get_type(env, ast));
}
case When: {
DeclareMatch(original, ast, When);
- ast_t *when_var = WrapAST(ast, Var, .name="when");
+ ast_t *when_var = WrapAST(ast, Var, .name = "when");
when_clause_t *new_clauses = NULL;
type_t *subject_t = get_type(env, original->subject);
for (when_clause_t *clause = original->clauses; clause; clause = clause->next) {
type_t *clause_type = get_clause_type(env, subject_t, clause);
if (clause_type->tag == AbortType || clause_type->tag == ReturnType) {
- new_clauses = new(when_clause_t, .pattern=clause->pattern, .body=clause->body, .next=new_clauses);
+ new_clauses =
+ new (when_clause_t, .pattern = clause->pattern, .body = clause->body, .next = new_clauses);
} else {
- ast_t *assign = WrapAST(clause->body, Assign,
- .targets=new(ast_list_t, .ast=when_var),
- .values=new(ast_list_t, .ast=clause->body));
- new_clauses = new(when_clause_t, .pattern=clause->pattern, .body=assign, .next=new_clauses);
+ ast_t *assign = WrapAST(clause->body, Assign, .targets = new (ast_list_t, .ast = when_var),
+ .values = new (ast_list_t, .ast = clause->body));
+ new_clauses = new (when_clause_t, .pattern = clause->pattern, .body = assign, .next = new_clauses);
}
}
REVERSE_LIST(new_clauses);
@@ -3609,19 +3594,18 @@ Text_t compile(env_t *env, ast_t *ast)
if (else_body) {
type_t *clause_type = get_type(env, else_body);
if (clause_type->tag != AbortType && clause_type->tag != ReturnType) {
- else_body = WrapAST(else_body, Assign,
- .targets=new(ast_list_t, .ast=when_var),
- .values=new(ast_list_t, .ast=else_body));
+ else_body = WrapAST(else_body, Assign, .targets = new (ast_list_t, .ast = when_var),
+ .values = new (ast_list_t, .ast = else_body));
}
}
type_t *t = get_type(env, ast);
env_t *when_env = fresh_scope(env);
set_binding(when_env, "when", t, Text("when"));
- return Texts(
- "({ ", compile_declaration(t, Text("when")), ";\n",
- compile_statement(when_env, WrapAST(ast, When, .subject=original->subject, .clauses=new_clauses, .else_body=else_body)),
- "when; })");
+ return Texts("({ ", compile_declaration(t, Text("when")), ";\n",
+ compile_statement(when_env, WrapAST(ast, When, .subject = original->subject,
+ .clauses = new_clauses, .else_body = else_body)),
+ "when; })");
}
case If: {
DeclareMatch(if_, ast, If);
@@ -3632,32 +3616,31 @@ Text_t compile(env_t *env, ast_t *ast)
Text_t condition_code;
if (condition->tag == Declare) {
DeclareMatch(decl, condition, Declare);
- if (decl->value == NULL)
- code_err(condition, "This declaration must have a value");
- type_t *condition_type =
- decl->type ? parse_type_ast(env, decl->type)
- : get_type(env, Match(condition, Declare)->value);
+ if (decl->value == NULL) code_err(condition, "This declaration must have a value");
+ type_t *condition_type =
+ decl->type ? parse_type_ast(env, decl->type) : get_type(env, Match(condition, Declare)->value);
if (condition_type->tag != OptionalType)
- code_err(condition, "This `if var := ...:` declaration should be an optional type, not ", type_to_str(condition_type));
+ code_err(condition,
+ "This `if var := ...:` declaration should be an "
+ "optional "
+ "type, not ",
+ type_to_str(condition_type));
- if (is_incomplete_type(condition_type))
- code_err(condition, "This type is incomplete!");
+ if (is_incomplete_type(condition_type)) code_err(condition, "This type is incomplete!");
decl_code = compile_statement(env, condition);
ast_t *var = Match(condition, Declare)->var;
truthy_scope = fresh_scope(env);
bind_statement(truthy_scope, condition);
condition_code = compile_condition(truthy_scope, var);
- set_binding(truthy_scope, Match(var, Var)->name,
- Match(condition_type, OptionalType)->type,
+ set_binding(truthy_scope, Match(var, Var)->name, Match(condition_type, OptionalType)->type,
optional_into_nonnone(condition_type, compile(truthy_scope, var)));
} else if (condition->tag == Var) {
type_t *condition_type = get_type(env, condition);
condition_code = compile_condition(env, condition);
if (condition_type->tag == OptionalType) {
truthy_scope = fresh_scope(env);
- set_binding(truthy_scope, Match(condition, Var)->name,
- Match(condition_type, OptionalType)->type,
+ set_binding(truthy_scope, Match(condition, Var)->name, Match(condition_type, OptionalType)->type,
optional_into_nonnone(condition_type, compile(truthy_scope, condition)));
}
} else {
@@ -3668,16 +3651,17 @@ Text_t compile(env_t *env, ast_t *ast)
type_t *false_type = get_type(falsey_scope, if_->else_body);
if (true_type->tag == AbortType || true_type->tag == ReturnType)
return Texts("({ ", decl_code, "if (", condition_code, ") ", compile_statement(truthy_scope, if_->body),
- "\n", compile(falsey_scope, if_->else_body), "; })");
+ "\n", compile(falsey_scope, if_->else_body), "; })");
else if (false_type->tag == AbortType || false_type->tag == ReturnType)
- return Texts("({ ", decl_code, "if (!(", condition_code, ")) ", compile_statement(falsey_scope, if_->else_body),
- "\n", compile(truthy_scope, if_->body), "; })");
+ return Texts("({ ", decl_code, "if (!(", condition_code, ")) ",
+ compile_statement(falsey_scope, if_->else_body), "\n", compile(truthy_scope, if_->body),
+ "; })");
else if (decl_code.length > 0)
return Texts("({ ", decl_code, "(", condition_code, ") ? ", compile(truthy_scope, if_->body), " : ",
- compile(falsey_scope, if_->else_body), ";})");
+ compile(falsey_scope, if_->else_body), ";})");
else
- return Texts("((", condition_code, ") ? ",
- compile(truthy_scope, if_->body), " : ", compile(falsey_scope, if_->else_body), ")");
+ return Texts("((", condition_code, ") ? ", compile(truthy_scope, if_->body), " : ",
+ compile(falsey_scope, if_->else_body), ")");
}
case Reduction: {
DeclareMatch(reduction, ast, Reduction);
@@ -3685,14 +3669,16 @@ Text_t compile(env_t *env, ast_t *ast)
type_t *iter_t = get_type(env, reduction->iter);
type_t *item_t = get_iterated_type(iter_t);
- if (!item_t) code_err(reduction->iter, "I couldn't figure out how to iterate over this type: ", type_to_str(iter_t));
+ if (!item_t)
+ code_err(reduction->iter, "I couldn't figure out how to iterate over this type: ", type_to_str(iter_t));
static int64_t next_id = 1;
ast_t *item = FakeAST(Var, String("$it", next_id++));
ast_t *body = LiteralCode(Text("{}")); // placeholder
- ast_t *loop = FakeAST(For, .vars=new(ast_list_t, .ast=item), .iter=reduction->iter, .body=body);
+ ast_t *loop = FakeAST(For, .vars = new (ast_list_t, .ast = item), .iter = reduction->iter, .body = body);
env_t *body_scope = for_scope(env, loop);
- if (op == Equals || op == NotEquals || op == LessThan || op == LessThanOrEquals || op == GreaterThan || op == GreaterThanOrEquals) {
+ if (op == Equals || op == NotEquals || op == LessThan || op == LessThanOrEquals || op == GreaterThan
+ || op == GreaterThanOrEquals) {
// Chained comparisons like ==, <, etc.
type_t *item_value_type = item_t;
ast_t *item_value = item;
@@ -3702,36 +3688,34 @@ Text_t compile(env_t *env, ast_t *ast)
item_value_type = get_type(body_scope, reduction->key);
}
- Text_t code = Texts(
- "({ // Reduction:\n",
- compile_declaration(item_value_type, Text("prev")), ";\n"
- "OptionalBool_t result = NONE_BOOL;\n"
- );
-
- ast_t *comparison = new(ast_t, .file=ast->file, .start=ast->start, .end=ast->end,
- .tag=op, .__data.Plus.lhs=LiteralCode(Text("prev"), .type=item_value_type), .__data.Plus.rhs=item_value);
- body->__data.InlineCCode.chunks = new(ast_list_t, .ast=FakeAST(TextLiteral, Texts(
- "if (result == NONE_BOOL) {\n"
- " prev = ", compile(body_scope, item_value), ";\n"
- " result = yes;\n"
- "} else {\n"
- " if (", compile(body_scope, comparison), ") {\n",
- " prev = ", compile(body_scope, item_value), ";\n",
- " } else {\n"
- " result = no;\n",
- " break;\n",
- " }\n",
- "}\n")));
+ Text_t code = Texts("({ // Reduction:\n", compile_declaration(item_value_type, Text("prev")),
+ ";\n"
+ "OptionalBool_t result = NONE_BOOL;\n");
+
+ ast_t *comparison = new (ast_t, .file = ast->file, .start = ast->start, .end = ast->end, .tag = op,
+ .__data.Plus.lhs = LiteralCode(Text("prev"), .type = item_value_type),
+ .__data.Plus.rhs = item_value);
+ body->__data.InlineCCode.chunks = new (
+ ast_list_t, .ast = FakeAST(TextLiteral, Texts("if (result == NONE_BOOL) {\n"
+ " prev = ",
+ compile(body_scope, item_value),
+ ";\n"
+ " result = yes;\n"
+ "} else {\n"
+ " if (",
+ compile(body_scope, comparison), ") {\n",
+ " prev = ", compile(body_scope, item_value), ";\n",
+ " } else {\n"
+ " result = no;\n",
+ " break;\n", " }\n", "}\n")));
code = Texts(code, compile_statement(env, loop), "\nresult;})");
return code;
} else if (op == Min || op == Max) {
// Min/max:
Text_t superlative = op == Min ? Text("min") : Text("max");
- Text_t code = Texts(
- "({ // Reduction:\n",
- compile_declaration(item_t, superlative), ";\n"
- "Bool_t has_value = no;\n"
- );
+ Text_t code = Texts("({ // Reduction:\n", compile_declaration(item_t, superlative),
+ ";\n"
+ "Bool_t has_value = no;\n");
Text_t item_code = compile(body_scope, item);
ast_e cmp_op = op == Min ? LessThan : GreaterThan;
@@ -3742,31 +3726,39 @@ Text_t compile(env_t *env, ast_t *ast)
Text_t superlative_key = op == Min ? Text("min_key") : Text("max_key");
code = Texts(code, compile_declaration(key_type, superlative_key), ";\n");
- ast_t *comparison = new(ast_t, .file=ast->file, .start=ast->start, .end=ast->end,
- .tag=cmp_op, .__data.Plus.lhs=LiteralCode(Text("key"), .type=key_type),
- .__data.Plus.rhs=LiteralCode(superlative_key, .type=key_type));
-
- body->__data.InlineCCode.chunks = new(ast_list_t, .ast=FakeAST(TextLiteral, Texts(
- compile_declaration(key_type, Text("key")), " = ", compile(key_scope, reduction->key), ";\n",
- "if (!has_value || ", compile(body_scope, comparison), ") {\n"
- " ", superlative, " = ", compile(body_scope, item), ";\n"
- " ", superlative_key, " = key;\n"
- " has_value = yes;\n"
- "}\n")));
+ ast_t *comparison = new (ast_t, .file = ast->file, .start = ast->start, .end = ast->end, .tag = cmp_op,
+ .__data.Plus.lhs = LiteralCode(Text("key"), .type = key_type),
+ .__data.Plus.rhs = LiteralCode(superlative_key, .type = key_type));
+
+ body->__data.InlineCCode.chunks = new (
+ ast_list_t, .ast = FakeAST(TextLiteral, Texts(compile_declaration(key_type, Text("key")), " = ",
+ compile(key_scope, reduction->key), ";\n",
+ "if (!has_value || ", compile(body_scope, comparison),
+ ") {\n"
+ " ",
+ superlative, " = ", compile(body_scope, item),
+ ";\n"
+ " ",
+ superlative_key,
+ " = key;\n"
+ " has_value = yes;\n"
+ "}\n")));
} else {
- ast_t *comparison = new(ast_t, .file=ast->file, .start=ast->start, .end=ast->end,
- .tag=cmp_op, .__data.Plus.lhs=item,
- .__data.Plus.rhs=LiteralCode(superlative, .type=item_t));
- body->__data.InlineCCode.chunks = new(ast_list_t, .ast=FakeAST(TextLiteral, Texts(
- "if (!has_value || ", compile(body_scope, comparison), ") {\n"
- " ", superlative, " = ", compile(body_scope, item), ";\n"
- " has_value = yes;\n"
- "}\n")));
+ ast_t *comparison =
+ new (ast_t, .file = ast->file, .start = ast->start, .end = ast->end, .tag = cmp_op,
+ .__data.Plus.lhs = item, .__data.Plus.rhs = LiteralCode(superlative, .type = item_t));
+ body->__data.InlineCCode.chunks = new (
+ ast_list_t, .ast = FakeAST(TextLiteral, Texts("if (!has_value || ", compile(body_scope, comparison),
+ ") {\n"
+ " ",
+ superlative, " = ", compile(body_scope, item),
+ ";\n"
+ " has_value = yes;\n"
+ "}\n")));
}
-
code = Texts(code, compile_statement(env, loop), "\nhas_value ? ", promote_to_optional(item_t, superlative),
- " : ", compile_none(item_t), ";})");
+ " : ", compile_none(item_t), ";})");
return code;
} else {
// Accumulator-style reductions like +, ++, *, etc.
@@ -3777,43 +3769,44 @@ Text_t compile(env_t *env, ast_t *ast)
item_value = reduction->key;
}
- Text_t code = Texts(
- "({ // Reduction:\n",
- compile_declaration(reduction_type, Text("reduction")), ";\n"
- "Bool_t has_value = no;\n"
- );
+ Text_t code = Texts("({ // Reduction:\n", compile_declaration(reduction_type, Text("reduction")),
+ ";\n"
+ "Bool_t has_value = no;\n");
- // For the special case of (or)/(and), we need to early out if we can:
+ // For the special case of (or)/(and), we need to early out if we
+ // can:
Text_t early_out = EMPTY_TEXT;
if (op == Compare) {
if (reduction_type->tag != IntType || Match(reduction_type, IntType)->bits != TYPE_IBITS32)
- code_err(ast, "<> reductions are only supported for Int32 values");
+ code_err(ast, "<> reductions are only supported for Int32 "
+ "values");
} else if (op == And) {
- if (reduction_type->tag == BoolType)
- early_out = Text("if (!reduction) break;");
+ if (reduction_type->tag == BoolType) early_out = Text("if (!reduction) break;");
else if (reduction_type->tag == OptionalType)
early_out = Texts("if (", check_none(reduction_type, Text("reduction")), ") break;");
} else if (op == Or) {
- if (reduction_type->tag == BoolType)
- early_out = Text("if (reduction) break;");
+ if (reduction_type->tag == BoolType) early_out = Text("if (reduction) break;");
else if (reduction_type->tag == OptionalType)
early_out = Texts("if (!", check_none(reduction_type, Text("reduction")), ") break;");
}
- ast_t *combination = new(ast_t, .file=ast->file, .start=ast->start, .end=ast->end,
- .tag=op, .__data.Plus.lhs=LiteralCode(Text("reduction"), .type=reduction_type),
- .__data.Plus.rhs=item_value);
- body->__data.InlineCCode.chunks = new(ast_list_t, .ast=FakeAST(TextLiteral, Texts(
- "if (!has_value) {\n"
- " reduction = ", compile(body_scope, item_value), ";\n"
- " has_value = yes;\n"
- "} else {\n"
- " reduction = ", compile(body_scope, combination), ";\n",
- early_out,
- "}\n")));
-
- code = Texts(code, compile_statement(env, loop), "\nhas_value ? ", promote_to_optional(reduction_type, Text("reduction")),
- " : ", compile_none(reduction_type), ";})");
+ ast_t *combination = new (ast_t, .file = ast->file, .start = ast->start, .end = ast->end, .tag = op,
+ .__data.Plus.lhs = LiteralCode(Text("reduction"), .type = reduction_type),
+ .__data.Plus.rhs = item_value);
+ body->__data.InlineCCode.chunks =
+ new (ast_list_t,
+ .ast = FakeAST(TextLiteral, Texts("if (!has_value) {\n"
+ " reduction = ",
+ compile(body_scope, item_value),
+ ";\n"
+ " has_value = yes;\n"
+ "} else {\n"
+ " reduction = ",
+ compile(body_scope, combination), ";\n", early_out, "}\n")));
+
+ code = Texts(code, compile_statement(env, loop), "\nhas_value ? ",
+ promote_to_optional(reduction_type, Text("reduction")), " : ", compile_none(reduction_type),
+ ";})");
return code;
}
}
@@ -3826,7 +3819,9 @@ Text_t compile(env_t *env, ast_t *ast)
DeclareMatch(info, value_t, TypeInfoType);
if (f->field[0] == '_') {
if (!type_eq(env->current_type, info->type))
- code_err(ast, "Fields that start with underscores are not accessible on types outside of the type definition.");
+ code_err(ast, "Fields that start with underscores are not "
+ "accessible "
+ "on types outside of the type definition.");
}
binding_t *b = get_binding(info->env, f->field);
if (!b) code_err(ast, "I couldn't find the field '", f->field, "' on this type");
@@ -3834,7 +3829,7 @@ Text_t compile(env_t *env, ast_t *ast)
return b->code;
}
case TextType: {
- const char *lang = Match(value_t, TextType)->lang;
+ const char *lang = Match(value_t, TextType)->lang;
if (lang && streq(f->field, "text")) {
Text_t text = compile_to_pointer_depth(env, f->fielded, 0, false);
return Texts("((Text_t)", text, ")");
@@ -3885,24 +3880,31 @@ Text_t compile(env_t *env, ast_t *ast)
if (streq(f->field, "items"))
return Texts("LIST_COPY((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries)");
else if (streq(f->field, "length"))
- return Texts("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries.length)");
+ return Texts("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false),
+ ").entries.length)");
code_err(ast, "There is no '", f->field, "' field on sets");
}
case TableType: {
if (streq(f->field, "length")) {
- return Texts("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries.length)");
+ return Texts("Int$from_int64((", compile_to_pointer_depth(env, f->fielded, 0, false),
+ ").entries.length)");
} else if (streq(f->field, "keys")) {
return Texts("LIST_COPY((", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries)");
} else if (streq(f->field, "values")) {
DeclareMatch(table, value_t, TableType);
- Text_t offset = Texts("offsetof(struct { ", compile_declaration(table->key_type, Text("k")), "; ", compile_declaration(table->value_type, Text("v")), "; }, v)");
- return Texts("({ List_t *entries = &(", compile_to_pointer_depth(env, f->fielded, 0, false), ").entries;\n"
- "LIST_INCREF(*entries);\n"
- "List_t values = *entries;\n"
- "values.data += ", offset, ";\n"
- "values; })");
+ Text_t offset = Texts("offsetof(struct { ", compile_declaration(table->key_type, Text("k")), "; ",
+ compile_declaration(table->value_type, Text("v")), "; }, v)");
+ return Texts("({ List_t *entries = &(", compile_to_pointer_depth(env, f->fielded, 0, false),
+ ").entries;\n"
+ "LIST_INCREF(*entries);\n"
+ "List_t values = *entries;\n"
+ "values.data += ",
+ offset,
+ ";\n"
+ "values; })");
} else if (streq(f->field, "fallback")) {
- return Texts("({ Table_t *_fallback = (", compile_to_pointer_depth(env, f->fielded, 0, false), ").fallback; _fallback ? *_fallback : NONE_TABLE; })");
+ return Texts("({ Table_t *_fallback = (", compile_to_pointer_depth(env, f->fielded, 0, false),
+ ").fallback; _fallback ? *_fallback : NONE_TABLE; })");
}
code_err(ast, "There is no '", f->field, "' field on tables");
}
@@ -3911,8 +3913,7 @@ Text_t compile(env_t *env, ast_t *ast)
env_t *module_env = Table$str_get(*env->imports, name);
return compile(module_env, WrapAST(ast, Var, f->field));
}
- default:
- code_err(ast, "Field accesses are not supported on ", type_to_str(fielded_t), " values");
+ default: code_err(ast, "Field accesses are not supported on ", type_to_str(fielded_t), " values");
}
}
case Index: {
@@ -3920,7 +3921,9 @@ Text_t compile(env_t *env, ast_t *ast)
type_t *indexed_type = get_type(env, indexing->indexed);
if (!indexing->index) {
if (indexed_type->tag != PointerType)
- code_err(ast, "Only pointers can use the '[]' operator to dereference the entire value.");
+ code_err(ast, "Only pointers can use the '[]' operator to "
+ "dereference "
+ "the entire value.");
DeclareMatch(ptr, indexed_type, PointerType);
if (ptr->pointed->tag == ListType) {
return Texts("*({ List_t *list = ", compile(env, indexing->indexed), "; LIST_INCREF(*list); list; })");
@@ -3939,77 +3942,90 @@ Text_t compile(env_t *env, ast_t *ast)
type_t *item_type = Match(container_t, ListType)->item_type;
Text_t list = compile_to_pointer_depth(env, indexing->indexed, 0, false);
file_t *f = indexing->index->file;
- Text_t index_code = indexing->index->tag == Int
- ? compile_int_to_type(env, indexing->index, Type(IntType, .bits=TYPE_IBITS64))
- : (index_t->tag == BigIntType ? Texts("Int64$from_int(", compile(env, indexing->index), ", no)")
- : Texts("(Int64_t)(", compile(env, indexing->index), ")"));
+ Text_t index_code =
+ indexing->index->tag == Int
+ ? compile_int_to_type(env, indexing->index, Type(IntType, .bits = TYPE_IBITS64))
+ : (index_t->tag == BigIntType ? Texts("Int64$from_int(", compile(env, indexing->index), ", no)")
+ : Texts("(Int64_t)(", compile(env, indexing->index), ")"));
if (indexing->unchecked)
return Texts("List_get_unchecked(", compile_type(item_type), ", ", list, ", ", index_code, ")");
else
return Texts("List_get(", compile_type(item_type), ", ", list, ", ", index_code, ", ",
- String((int64_t)(indexing->index->start - f->text)), ", ",
- String((int64_t)(indexing->index->end - f->text)),
- ")");
+ String((int64_t)(indexing->index->start - f->text)), ", ",
+ String((int64_t)(indexing->index->end - f->text)), ")");
} else if (container_t->tag == TableType) {
DeclareMatch(table_type, container_t, TableType);
- if (indexing->unchecked)
- code_err(ast, "Table indexes cannot be unchecked");
+ if (indexing->unchecked) code_err(ast, "Table indexes cannot be unchecked");
if (table_type->default_value) {
- return Texts("Table$get_or_default(",
- compile_to_pointer_depth(env, indexing->indexed, 0, false), ", ",
- compile_type(table_type->key_type), ", ",
- compile_type(table_type->value_type), ", ",
- compile(env, indexing->index), ", ",
- compile_to_type(env, table_type->default_value, table_type->value_type), ", ",
- compile_type_info(container_t), ")");
+ return Texts("Table$get_or_default(", compile_to_pointer_depth(env, indexing->indexed, 0, false), ", ",
+ compile_type(table_type->key_type), ", ", compile_type(table_type->value_type), ", ",
+ compile(env, indexing->index), ", ",
+ compile_to_type(env, table_type->default_value, table_type->value_type), ", ",
+ compile_type_info(container_t), ")");
} else {
- return Texts("Table$get_optional(",
- compile_to_pointer_depth(env, indexing->indexed, 0, false), ", ",
- compile_type(table_type->key_type), ", ",
- compile_type(table_type->value_type), ", ",
- compile(env, indexing->index), ", "
- "_, ", promote_to_optional(table_type->value_type, Text("(*_)")), ", ",
- compile_none(table_type->value_type), ", ",
- compile_type_info(container_t), ")");
+ return Texts("Table$get_optional(", compile_to_pointer_depth(env, indexing->indexed, 0, false), ", ",
+ compile_type(table_type->key_type), ", ", compile_type(table_type->value_type), ", ",
+ compile(env, indexing->index),
+ ", "
+ "_, ",
+ promote_to_optional(table_type->value_type, Text("(*_)")), ", ",
+ compile_none(table_type->value_type), ", ", compile_type_info(container_t), ")");
}
} else if (container_t->tag == TextType) {
- return Texts("Text$cluster(", compile_to_pointer_depth(env, indexing->indexed, 0, false), ", ", compile_to_type(env, indexing->index, Type(BigIntType)), ")");
+ return Texts("Text$cluster(", compile_to_pointer_depth(env, indexing->indexed, 0, false), ", ",
+ compile_to_type(env, indexing->index, Type(BigIntType)), ")");
} else {
code_err(ast, "Indexing is not supported for type: ", type_to_str(container_t));
}
}
case InlineCCode: {
type_t *t = get_type(env, ast);
- if (t->tag == VoidType)
- return Texts("{\n", compile_statement(env, ast), "\n}");
- else
- return compile_statement(env, ast);
+ if (t->tag == VoidType) return Texts("{\n", compile_statement(env, ast), "\n}");
+ else return compile_statement(env, ast);
}
case Use: code_err(ast, "Compiling 'use' as expression!");
case Defer: code_err(ast, "Compiling 'defer' as expression!");
case Extern: code_err(ast, "Externs are not supported as expressions");
case TableEntry: code_err(ast, "Table entries should not be compiled directly");
- case Declare: case Assign: case UPDATE_CASES: case For: case While: case Repeat: case StructDef: case LangDef: case Extend:
- case EnumDef: case FunctionDef: case ConvertDef: case Skip: case Stop: case Pass: case Return: case DocTest: case Assert:
- code_err(ast, "This is not a valid expression");
- default: case Unknown: code_err(ast, "Unknown AST: ", ast_to_sexp_str(ast));
+ case Declare:
+ case Assign:
+ case UPDATE_CASES:
+ case For:
+ case While:
+ case Repeat:
+ case StructDef:
+ case LangDef:
+ case Extend:
+ case EnumDef:
+ case FunctionDef:
+ case ConvertDef:
+ case Skip:
+ case Stop:
+ case Pass:
+ case Return:
+ case DocTest:
+ case Assert: code_err(ast, "This is not a valid expression");
+ default:
+ case Unknown: code_err(ast, "Unknown AST: ", ast_to_sexp_str(ast));
}
return EMPTY_TEXT;
}
-Text_t compile_type_info(type_t *t)
-{
+Text_t compile_type_info(type_t *t) {
if (t == NULL) compiler_err(NULL, NULL, NULL, "Attempt to compile a NULL type");
if (t == PATH_TYPE) return Text("&Path$info");
else if (t == PATH_TYPE_TYPE) return Text("&PathType$info");
switch (t->tag) {
- case BoolType: case ByteType: case IntType: case BigIntType: case NumType: case CStringType:
- return Texts("&", type_to_text(t), "$info");
+ case BoolType:
+ case ByteType:
+ case IntType:
+ case BigIntType:
+ case NumType:
+ case CStringType: return Texts("&", type_to_text(t), "$info");
case TextType: {
DeclareMatch(text, t, TextType);
- if (!text->lang || streq(text->lang, "Text"))
- return Text("&Text$info");
+ if (!text->lang || streq(text->lang, "Text")) return Text("&Text$info");
return Texts("(&", namespace_name(text->env, text->env->namespace, Text("$info")), ")");
}
case StructType: {
@@ -4047,20 +4063,18 @@ Text_t compile_type_info(type_t *t)
}
case OptionalType: {
type_t *non_optional = Match(t, OptionalType)->type;
- return Texts("Optional$info(sizeof(", compile_type(non_optional),
- "), __alignof__(", compile_type(non_optional), "), ", compile_type_info(non_optional), ")");
+ return Texts("Optional$info(sizeof(", compile_type(non_optional), "), __alignof__(", compile_type(non_optional),
+ "), ", compile_type_info(non_optional), ")");
}
case TypeInfoType: return Texts("Type$info(", quoted_text(type_to_text(Match(t, TypeInfoType)->type)), ")");
case MemoryType: return Text("&Memory$info");
case VoidType: return Text("&Void$info");
- default:
- compiler_err(NULL, 0, 0, "I couldn't convert to a type info: ", type_to_str(t));
+ default: compiler_err(NULL, 0, 0, "I couldn't convert to a type info: ", type_to_str(t));
}
return EMPTY_TEXT;
}
-static Text_t get_flag_options(type_t *t, const char *separator)
-{
+static Text_t get_flag_options(type_t *t, const char *separator) {
if (t->tag == BoolType) {
return Text("yes|no");
} else if (t->tag == EnumType) {
@@ -4077,8 +4091,7 @@ static Text_t get_flag_options(type_t *t, const char *separator)
}
}
-Text_t compile_cli_arg_call(env_t *env, Text_t fn_name, type_t *fn_type, const char *version)
-{
+Text_t compile_cli_arg_call(env_t *env, Text_t fn_name, type_t *fn_type, const char *version) {
DeclareMatch(fn_info, fn_type, FunctionType);
env_t *main_env = fresh_scope(env);
@@ -4106,39 +4119,32 @@ Text_t compile_cli_arg_call(env_t *env, Text_t fn_name, type_t *fn_type, const c
if (strlen(arg->name) == 1) {
if (t->tag == BoolType || (t->tag == OptionalType && Match(t, OptionalType)->type->tag == BoolType))
usage = Texts(usage, "[-", flag, "]");
- else
- usage = Texts(usage, "[-", flag, " ", get_flag_options(t, "|"), "]");
+ else usage = Texts(usage, "[-", flag, " ", get_flag_options(t, "|"), "]");
} else {
if (t->tag == BoolType || (t->tag == OptionalType && Match(t, OptionalType)->type->tag == BoolType))
usage = Texts(usage, "[--", flag, "]");
- else if (t->tag == ListType)
- usage = Texts(usage, "[--", flag, " ", get_flag_options(t, "|"), "]");
- else
- usage = Texts(usage, "[--", flag, "=", get_flag_options(t, "|"), "]");
+ else if (t->tag == ListType) usage = Texts(usage, "[--", flag, " ", get_flag_options(t, "|"), "]");
+ else usage = Texts(usage, "[--", flag, "=", get_flag_options(t, "|"), "]");
}
} else {
- if (t->tag == BoolType)
- usage = Texts(usage, "<--", flag, "|--no-", flag, ">");
- else if (t->tag == EnumType)
- usage = Texts(usage, get_flag_options(t, "|"));
- else if (t->tag == ListType)
- usage = Texts(usage, "[", flag, "...]");
- else
- usage = Texts(usage, "<", flag, ">");
+ if (t->tag == BoolType) usage = Texts(usage, "<--", flag, "|--no-", flag, ">");
+ else if (t->tag == EnumType) usage = Texts(usage, get_flag_options(t, "|"));
+ else if (t->tag == ListType) usage = Texts(usage, "[", flag, "...]");
+ else usage = Texts(usage, "<", flag, ">");
}
}
- code = Texts(code, "Text_t usage = Texts(Text(\"Usage: \"), Text$from_str(argv[0])",
- usage.length == 0 ? EMPTY_TEXT : Texts(", Text(", quoted_text(usage), ")"), ");\n");
+ code = Texts(code,
+ "Text_t usage = Texts(Text(\"Usage: \"), "
+ "Text$from_str(argv[0])",
+ usage.length == 0 ? EMPTY_TEXT : Texts(", Text(", quoted_text(usage), ")"), ");\n");
}
-
for (arg_t *arg = fn_info->args; arg; arg = arg->next) {
- type_t *opt_type = arg->type->tag == OptionalType ? arg->type : Type(OptionalType, .type=arg->type);
+ type_t *opt_type = arg->type->tag == OptionalType ? arg->type : Type(OptionalType, .type = arg->type);
code = Texts(code, compile_declaration(opt_type, Texts("_$", arg->name)));
if (arg->default_val) {
Text_t default_val = compile(env, arg->default_val);
- if (arg->type->tag != OptionalType)
- default_val = promote_to_optional(arg->type, default_val);
+ if (arg->type->tag != OptionalType) default_val = promote_to_optional(arg->type, default_val);
code = Texts(code, " = ", default_val);
} else {
code = Texts(code, " = ", compile_none(arg->type));
@@ -4150,17 +4156,15 @@ Text_t compile_cli_arg_call(env_t *env, Text_t fn_name, type_t *fn_type, const c
code = Texts(code, "tomo_parse_args(argc, argv, ", usage_code, ", ", help_code, ", ", version_code);
for (arg_t *arg = fn_info->args; arg; arg = arg->next) {
code = Texts(code, ",\n{", quoted_text(Text$replace(Text$from_str(arg->name), Text("_"), Text("-"))), ", ",
- (arg->default_val || arg->type->tag == OptionalType) ? "false" : "true", ", ",
- compile_type_info(arg->type),
- ", &", Texts("_$", arg->name), "}");
+ (arg->default_val || arg->type->tag == OptionalType) ? "false" : "true", ", ",
+ compile_type_info(arg->type), ", &", Texts("_$", arg->name), "}");
}
code = Texts(code, ");\n");
code = Texts(code, fn_name, "(");
for (arg_t *arg = fn_info->args; arg; arg = arg->next) {
Text_t arg_code = Texts("_$", arg->name);
- if (arg->type->tag != OptionalType)
- arg_code = optional_into_nonnone(arg->type, arg_code);
+ if (arg->type->tag != OptionalType) arg_code = optional_into_nonnone(arg->type, arg_code);
code = Texts(code, arg_code);
if (arg->next) code = Texts(code, ", ");
@@ -4169,8 +4173,7 @@ Text_t compile_cli_arg_call(env_t *env, Text_t fn_name, type_t *fn_type, const c
return code;
}
-Text_t compile_function(env_t *env, Text_t name_code, ast_t *ast, Text_t *staticdefs)
-{
+Text_t compile_function(env_t *env, Text_t name_code, ast_t *ast, Text_t *staticdefs) {
bool is_private = false;
const char *function_name;
arg_ast_t *args;
@@ -4193,7 +4196,10 @@ Text_t compile_function(env_t *env, Text_t name_code, ast_t *ast, Text_t *static
ret_t = convertdef->ret_type ? parse_type_ast(env, convertdef->ret_type) : Type(VoidType);
function_name = get_type_name(ret_t);
if (!function_name)
- code_err(ast, "Conversions are only supported for text, struct, and enum types, not ", type_to_str(ret_t));
+ code_err(ast,
+ "Conversions are only supported for text, struct, and enum "
+ "types, not ",
+ type_to_str(ret_t));
body = convertdef->body;
cache = convertdef->cache;
is_inline = convertdef->is_inline;
@@ -4212,21 +4218,17 @@ Text_t compile_function(env_t *env, Text_t name_code, ast_t *ast, Text_t *static
arg_signature = Texts(arg_signature, ")");
Text_t ret_type_code = compile_type(ret_t);
- if (ret_t->tag == AbortType)
- ret_type_code = Texts("__attribute__((noreturn)) _Noreturn ", ret_type_code);
+ if (ret_t->tag == AbortType) ret_type_code = Texts("__attribute__((noreturn)) _Noreturn ", ret_type_code);
- if (is_private)
- *staticdefs = Texts(*staticdefs, "static ", ret_type_code, " ", name_code, arg_signature, ";\n");
+ if (is_private) *staticdefs = Texts(*staticdefs, "static ", ret_type_code, " ", name_code, arg_signature, ";\n");
Text_t code;
if (cache) {
code = Texts("static ", ret_type_code, " ", name_code, "$uncached", arg_signature);
} else {
code = Texts(ret_type_code, " ", name_code, arg_signature);
- if (is_inline)
- code = Texts("INLINE ", code);
- if (!is_private)
- code = Texts("public ", code);
+ if (is_inline) code = Texts("INLINE ", code);
+ if (!is_private) code = Texts("public ", code);
}
env_t *body_scope = fresh_scope(env);
@@ -4245,72 +4247,92 @@ Text_t compile_function(env_t *env, Text_t name_code, ast_t *ast, Text_t *static
type_t *body_type = get_type(body_scope, body);
if (ret_t->tag == AbortType) {
- if (body_type->tag != AbortType)
- code_err(ast, "This function can reach the end without aborting!");
+ if (body_type->tag != AbortType) code_err(ast, "This function can reach the end without aborting!");
} else if (ret_t->tag == VoidType) {
if (body_type->tag == AbortType)
- code_err(ast, "This function will always abort before it reaches the end, but it's declared as having a Void return. It should be declared as an Abort return instead.");
+ code_err(ast, "This function will always abort before it reaches the "
+ "end, but it's declared as having a Void return. It should "
+ "be declared as an Abort return instead.");
} else {
if (body_type->tag != ReturnType && body_type->tag != AbortType)
- code_err(ast, "This function looks like it can reach the end without returning a ", type_to_str(ret_t), " value! \n "
- "If this is not the case, please add a call to `fail(\"Unreachable\")` at the end of the function to help the compiler out.");
+ code_err(ast,
+ "This function looks like it can reach the end without "
+ "returning a ",
+ type_to_str(ret_t),
+ " value! \n "
+ "If this is not the case, please add a call to "
+ "`fail(\"Unreachable\")` at the end of the function to "
+ "help the "
+ "compiler out.");
}
Text_t body_code = Texts("{\n", compile_inline_block(body_scope, body), "}\n");
Text_t definition = with_source_info(env, ast, Texts(code, " ", body_code, "\n"));
if (cache && args == NULL) { // no-args cache just uses a static var
- Text_t wrapper = Texts(
- is_private ? EMPTY_TEXT : Text("public "), ret_type_code, " ", name_code, "(void) {\n"
- "static ", compile_declaration(ret_t, Text("cached_result")), ";\n",
- "static bool initialized = false;\n",
- "if (!initialized) {\n"
- "\tcached_result = ", name_code, "$uncached();\n",
- "\tinitialized = true;\n",
- "}\n",
- "return cached_result;\n"
- "}\n");
+ Text_t wrapper =
+ Texts(is_private ? EMPTY_TEXT : Text("public "), ret_type_code, " ", name_code,
+ "(void) {\n"
+ "static ",
+ compile_declaration(ret_t, Text("cached_result")), ";\n", "static bool initialized = false;\n",
+ "if (!initialized) {\n"
+ "\tcached_result = ",
+ name_code, "$uncached();\n", "\tinitialized = true;\n", "}\n",
+ "return cached_result;\n"
+ "}\n");
definition = Texts(definition, wrapper);
} else if (cache && cache->tag == Int) {
assert(args);
OptionalInt64_t cache_size = Int64$parse(Text$from_str(Match(cache, Int)->str), NULL);
Text_t pop_code = EMPTY_TEXT;
if (cache->tag == Int && !cache_size.is_none && cache_size.value > 0) {
- // FIXME: this currently just deletes the first entry, but this should be more like a
- // least-recently-used cache eviction policy or least-frequently-used
+ // FIXME: this currently just deletes the first entry, but this
+ // should be more like a least-recently-used cache eviction policy
+ // or least-frequently-used
pop_code = Texts("if (cache.entries.length > ", String(cache_size.value),
- ") Table$remove(&cache, cache.entries.data + cache.entries.stride*0, table_type);\n");
+ ") Table$remove(&cache, cache.entries.data + "
+ "cache.entries.stride*0, table_type);\n");
}
if (!args->next) {
// Single-argument functions have simplified caching logic
type_t *arg_type = get_arg_ast_type(env, args);
- Text_t wrapper = Texts(
- is_private ? EMPTY_TEXT : Text("public "), ret_type_code, " ", name_code, arg_signature, "{\n"
- "static Table_t cache = {};\n",
- "const TypeInfo_t *table_type = Table$info(", compile_type_info(arg_type), ", ", compile_type_info(ret_t), ");\n",
- compile_declaration(Type(PointerType, .pointed=ret_t), Text("cached")), " = Table$get_raw(cache, &_$", args->name, ", table_type);\n"
- "if (cached) return *cached;\n",
- compile_declaration(ret_t, Text("ret")), " = ", name_code, "$uncached(_$", args->name, ");\n",
- pop_code,
- "Table$set(&cache, &_$", args->name, ", &ret, table_type);\n"
- "return ret;\n"
- "}\n");
+ Text_t wrapper =
+ Texts(is_private ? EMPTY_TEXT : Text("public "), ret_type_code, " ", name_code, arg_signature,
+ "{\n"
+ "static Table_t cache = {};\n",
+ "const TypeInfo_t *table_type = Table$info(", compile_type_info(arg_type), ", ",
+ compile_type_info(ret_t), ");\n",
+ compile_declaration(Type(PointerType, .pointed = ret_t), Text("cached")),
+ " = Table$get_raw(cache, &_$", args->name,
+ ", table_type);\n"
+ "if (cached) return *cached;\n",
+ compile_declaration(ret_t, Text("ret")), " = ", name_code, "$uncached(_$", args->name, ");\n",
+ pop_code, "Table$set(&cache, &_$", args->name,
+ ", &ret, table_type);\n"
+ "return ret;\n"
+ "}\n");
definition = Texts(definition, wrapper);
} else {
- // Multi-argument functions use a custom struct type (only defined internally) as a cache key:
+ // Multi-argument functions use a custom struct type (only defined
+ // internally) as a cache key:
arg_t *fields = NULL;
for (arg_ast_t *arg = args; arg; arg = arg->next)
- fields = new(arg_t, .name=arg->name, .type=get_arg_ast_type(env, arg), .next=fields);
+ fields = new (arg_t, .name = arg->name, .type = get_arg_ast_type(env, arg), .next = fields);
REVERSE_LIST(fields);
- type_t *t = Type(StructType, .name=String("func$", get_line_number(ast->file, ast->start), "$args"), .fields=fields, .env=env);
+ type_t *t = Type(StructType, .name = String("func$", get_line_number(ast->file, ast->start), "$args"),
+ .fields = fields, .env = env);
int64_t num_fields = used_names.entries.length;
const char *metamethods = is_packed_data(t) ? "PackedData$metamethods" : "Struct$metamethods";
- Text_t args_typeinfo = Texts("((TypeInfo_t[1]){{.size=sizeof(args), .align=__alignof__(args), .metamethods=", metamethods,
- ", .tag=StructInfo, .StructInfo.name=\"FunctionArguments\", "
- ".StructInfo.num_fields=", String(num_fields),
- ", .StructInfo.fields=(NamedType_t[", String(num_fields), "]){");
+ Text_t args_typeinfo =
+ Texts("((TypeInfo_t[1]){{.size=sizeof(args), "
+ ".align=__alignof__(args), .metamethods=",
+ metamethods,
+ ", .tag=StructInfo, "
+ ".StructInfo.name=\"FunctionArguments\", "
+ ".StructInfo.num_fields=",
+ String(num_fields), ", .StructInfo.fields=(NamedType_t[", String(num_fields), "]){");
Text_t args_type = Text("struct { ");
for (arg_t *f = fields; f; f = f->next) {
args_typeinfo = Texts(args_typeinfo, "{\"", f->name, "\", ", compile_type_info(f->type), "}");
@@ -4325,14 +4347,17 @@ Text_t compile_function(env_t *env, Text_t name_code, ast_t *ast, Text_t *static
all_args = Texts(all_args, "_$", arg->name, arg->next ? Text(", ") : EMPTY_TEXT);
Text_t wrapper = Texts(
- is_private ? EMPTY_TEXT : Text("public "), ret_type_code, " ", name_code, arg_signature, "{\n"
+ is_private ? EMPTY_TEXT : Text("public "), ret_type_code, " ", name_code, arg_signature,
+ "{\n"
"static Table_t cache = {};\n",
- args_type, " args = {", all_args, "};\n"
- "const TypeInfo_t *table_type = Table$info(", args_typeinfo, ", ", compile_type_info(ret_t), ");\n",
- compile_declaration(Type(PointerType, .pointed=ret_t), Text("cached")), " = Table$get_raw(cache, &args, table_type);\n"
+ args_type, " args = {", all_args,
+ "};\n"
+ "const TypeInfo_t *table_type = Table$info(",
+ args_typeinfo, ", ", compile_type_info(ret_t), ");\n",
+ compile_declaration(Type(PointerType, .pointed = ret_t), Text("cached")),
+ " = Table$get_raw(cache, &args, table_type);\n"
"if (cached) return *cached;\n",
- compile_declaration(ret_t, Text("ret")), " = ", name_code, "$uncached(", all_args, ");\n",
- pop_code,
+ compile_declaration(ret_t, Text("ret")), " = ", name_code, "$uncached(", all_args, ");\n", pop_code,
"Table$set(&cache, &args, &ret, table_type);\n"
"return ret;\n"
"}\n");
@@ -4348,22 +4373,22 @@ Text_t compile_function(env_t *env, Text_t name_code, ast_t *ast, Text_t *static
text = Texts(text, type_to_text(get_arg_ast_type(env, arg)));
if (arg->next) text = Texts(text, ", ");
}
- if (ret_t && ret_t->tag != VoidType)
- text = Texts(text, "->", type_to_text(ret_t));
+ if (ret_t && ret_t->tag != VoidType) text = Texts(text, "->", type_to_text(ret_t));
text = Texts(text, ")");
return definition;
}
-Text_t compile_top_level_code(env_t *env, ast_t *ast)
-{
+Text_t compile_top_level_code(env_t *env, ast_t *ast) {
if (!ast) return EMPTY_TEXT;
switch (ast->tag) {
case Use: {
// DeclareMatch(use, ast, Use);
// if (use->what == USE_C_CODE) {
- // Path_t path = Path$relative_to(Path$from_str(use->path), Path(".build"));
- // return Texts("#include \"", Path$as_c_string(path), "\"\n");
+ // Path_t path = Path$relative_to(Path$from_str(use->path),
+ // Path(".build")); return Texts("#include \"",
+ // Path$as_c_string(path),
+ // "\"\n");
// }
return EMPTY_TEXT;
}
@@ -4377,31 +4402,32 @@ Text_t compile_top_level_code(env_t *env, ast_t *ast)
bool is_private = decl_name[0] == '_';
if ((decl->value && is_constant(env, decl->value)) || (!decl->value && !has_heap_memory(t))) {
set_binding(env, decl_name, t, full_name);
- return Texts(
- is_private ? "static " : "public ",
- compile_declaration(t, full_name), " = ", val_code, ";\n");
+ return Texts(is_private ? "static " : "public ", compile_declaration(t, full_name), " = ", val_code, ";\n");
} else {
Text_t init_var = namespace_name(env, env->namespace, Texts(decl_name, "$$initialized"));
Text_t checked_access = Texts("check_initialized(", full_name, ", ", init_var, ", \"", decl_name, "\")");
set_binding(env, decl_name, t, checked_access);
Text_t initialized_name = namespace_name(env, env->namespace, Texts(decl_name, "$$initialized"));
- return Texts(
- "static bool ", initialized_name, " = false;\n",
- is_private ? "static " : "public ",
- compile_declaration(t, full_name), ";\n");
+ return Texts("static bool ", initialized_name, " = false;\n", is_private ? "static " : "public ",
+ compile_declaration(t, full_name), ";\n");
}
}
case FunctionDef: {
- Text_t name_code = namespace_name(env, env->namespace, Text$from_str(Match(Match(ast, FunctionDef)->name, Var)->name));
+ Text_t name_code =
+ namespace_name(env, env->namespace, Text$from_str(Match(Match(ast, FunctionDef)->name, Var)->name));
return compile_function(env, name_code, ast, &env->code->staticdefs);
}
case ConvertDef: {
type_t *type = get_function_def_type(env, ast);
const char *name = get_type_name(Match(type, FunctionType)->ret);
if (!name)
- code_err(ast, "Conversions are only supported for text, struct, and enum types, not ", type_to_str(Match(type, FunctionType)->ret));
- Text_t name_code = namespace_name(env, env->namespace, Texts(name, "$", String(get_line_number(ast->file, ast->start))));
+ code_err(ast,
+ "Conversions are only supported for text, struct, and enum "
+ "types, not ",
+ type_to_str(Match(type, FunctionType)->ret));
+ Text_t name_code =
+ namespace_name(env, env->namespace, Texts(name, "$", String(get_line_number(ast->file, ast->start))));
return compile_function(env, name_code, ast, &env->code->staticdefs);
}
case StructDef: {
@@ -4421,9 +4447,10 @@ Text_t compile_top_level_code(env_t *env, ast_t *ast)
}
case LangDef: {
DeclareMatch(def, ast, LangDef);
- Text_t code = Texts("public const TypeInfo_t ", namespace_name(env, env->namespace, Texts(def->name, "$$info")),
- " = {", String((int64_t)sizeof(Text_t)), ", ", String((int64_t)__alignof__(Text_t)),
- ", .metamethods=Text$metamethods, .tag=TextInfo, .TextInfo={", quoted_str(def->name), "}};\n");
+ Text_t code =
+ Texts("public const TypeInfo_t ", namespace_name(env, env->namespace, Texts(def->name, "$$info")), " = {",
+ String((int64_t)sizeof(Text_t)), ", ", String((int64_t)__alignof__(Text_t)),
+ ", .metamethods=Text$metamethods, .tag=TextInfo, .TextInfo={", quoted_str(def->name), "}};\n");
env_t *ns_env = namespace_env(env, def->name);
return Texts(code, def->namespace ? compile_top_level_code(ns_env, def->namespace) : EMPTY_TEXT);
}
@@ -4433,10 +4460,10 @@ Text_t compile_top_level_code(env_t *env, ast_t *ast)
if (!b || b->type->tag != TypeInfoType)
code_err(ast, "'", extend->name, "' is not the name of any type I recognize.");
env_t *ns_env = Match(b->type, TypeInfoType)->env;
- env_t *extended = new(env_t);
+ env_t *extended = new (env_t);
*extended = *ns_env;
- extended->locals = new(Table_t, .fallback=env->locals);
- extended->namespace_bindings = new(Table_t, .fallback=env->namespace_bindings);
+ extended->locals = new (Table_t, .fallback = env->locals);
+ extended->namespace_bindings = new (Table_t, .fallback = env->namespace_bindings);
extended->id_suffix = env->id_suffix;
return compile_top_level_code(extended, extend->body);
}
@@ -4452,8 +4479,7 @@ Text_t compile_top_level_code(env_t *env, ast_t *ast)
}
}
-static void initialize_vars_and_statics(env_t *env, ast_t *ast)
-{
+static void initialize_vars_and_statics(env_t *env, ast_t *ast) {
if (!ast) return;
for (ast_list_t *stmt = Match(ast, Block)->statements; stmt; stmt = stmt->next) {
@@ -4469,13 +4495,10 @@ static void initialize_vars_and_statics(env_t *env, ast_t *ast)
Text_t val_code = compile_declared_value(env, stmt->ast);
if ((decl->value && !is_constant(env, decl->value)) || (!decl->value && has_heap_memory(t))) {
Text_t initialized_name = namespace_name(env, env->namespace, Texts(decl_name, "$$initialized"));
- env->code->variable_initializers = Texts(
- env->code->variable_initializers,
- with_source_info(
- env, stmt->ast,
- Texts(
- full_name, " = ", val_code, ",\n",
- initialized_name, " = true;\n")));
+ env->code->variable_initializers =
+ Texts(env->code->variable_initializers,
+ with_source_info(env, stmt->ast,
+ Texts(full_name, " = ", val_code, ",\n", initialized_name, " = true;\n")));
}
} else if (stmt->ast->tag == StructDef) {
initialize_vars_and_statics(namespace_env(env, Match(stmt->ast, StructDef)->name),
@@ -4498,8 +4521,7 @@ static void initialize_vars_and_statics(env_t *env, ast_t *ast)
}
}
-Text_t compile_file(env_t *env, ast_t *ast)
-{
+Text_t compile_file(env_t *env, ast_t *ast) {
Text_t top_level_code = compile_top_level_code(env, ast);
Text_t includes = EMPTY_TEXT;
Text_t use_imports = EMPTY_TEXT;
@@ -4520,27 +4542,18 @@ Text_t compile_file(env_t *env, ast_t *ast)
initialize_vars_and_statics(env, ast);
const char *name = file_base_name(ast->file->filename);
- return Texts(
- env->do_source_mapping ? Texts("#line 1 ", quoted_str(ast->file->filename), "\n") : EMPTY_TEXT,
- "#define __SOURCE_FILE__ ", quoted_str(ast->file->filename), "\n",
- "#include <tomo_"TOMO_VERSION"/tomo.h>\n"
- "#include \"", name, ".tm.h\"\n\n",
- includes,
- env->code->local_typedefs, "\n",
- env->code->lambdas, "\n",
- env->code->staticdefs, "\n",
- top_level_code,
- "public void ", namespace_name(env, env->namespace, Text("$initialize")), "(void) {\n",
- "static bool initialized = false;\n",
- "if (initialized) return;\n",
- "initialized = true;\n",
- use_imports,
- env->code->variable_initializers,
- "}\n");
+ return Texts(env->do_source_mapping ? Texts("#line 1 ", quoted_str(ast->file->filename), "\n") : EMPTY_TEXT,
+ "#define __SOURCE_FILE__ ", quoted_str(ast->file->filename), "\n",
+ "#include <tomo_" TOMO_VERSION "/tomo.h>\n"
+ "#include \"",
+ name, ".tm.h\"\n\n", includes, env->code->local_typedefs, "\n", env->code->lambdas, "\n",
+ env->code->staticdefs, "\n", top_level_code, "public void ",
+ namespace_name(env, env->namespace, Text("$initialize")), "(void) {\n",
+ "static bool initialized = false;\n", "if (initialized) return;\n", "initialized = true;\n",
+ use_imports, env->code->variable_initializers, "}\n");
}
-Text_t compile_statement_type_header(env_t *env, Path_t header_path, ast_t *ast)
-{
+Text_t compile_statement_type_header(env_t *env, Path_t header_path, ast_t *ast) {
switch (ast->tag) {
case Use: {
DeclareMatch(use, ast, Use);
@@ -4552,9 +4565,10 @@ Text_t compile_statement_type_header(env_t *env, Path_t header_path, ast_t *ast)
module_info_t mod = get_module_info(ast);
glob_t tm_files;
const char *folder = mod.version ? String(mod.name, "_", mod.version) : mod.name;
- if (glob(String(TOMO_PREFIX"/share/tomo_"TOMO_VERSION"/installed/", folder, "/[!._0-9]*.tm"), GLOB_TILDE, NULL, &tm_files) != 0) {
- if (!try_install_module(mod))
- code_err(ast, "Could not find library");
+ if (glob(String(TOMO_PREFIX "/share/tomo_" TOMO_VERSION "/installed/", folder, "/[!._0-9]*.tm"), GLOB_TILDE,
+ NULL, &tm_files)
+ != 0) {
+ if (!try_install_module(mod)) code_err(ast, "Could not find library");
}
Text_t includes = EMPTY_TEXT;
@@ -4581,8 +4595,7 @@ Text_t compile_statement_type_header(env_t *env, Path_t header_path, ast_t *ast)
Path_t used_path = Path$resolved(Path$from_str(use->path), source_dir);
return Texts("#include \"", Path$as_c_string(Path$relative_to(used_path, build_dir)), "\"\n");
}
- default:
- return EMPTY_TEXT;
+ default: return EMPTY_TEXT;
}
}
case StructDef: {
@@ -4595,23 +4608,25 @@ Text_t compile_statement_type_header(env_t *env, Path_t header_path, ast_t *ast)
DeclareMatch(def, ast, LangDef);
return Texts(
// Constructor macro:
- "#define ", namespace_name(env, env->namespace, Text$from_str(def->name)),
- "(text) ((", namespace_name(env, env->namespace, Texts(def->name, "$$type")), "){.length=sizeof(text)-1, .tag=TEXT_ASCII, .ascii=\"\" text})\n"
- "#define ", namespace_name(env, env->namespace, Text$from_str(def->name)),
- "s(...) ((", namespace_name(env, env->namespace, Texts(def->name, "$$type")), ")Texts(__VA_ARGS__))\n"
- "extern const TypeInfo_t ", namespace_name(env, env->namespace, Texts(def->name, Text("$$info"))), ";\n"
- );
+ "#define ", namespace_name(env, env->namespace, Text$from_str(def->name)), "(text) ((",
+ namespace_name(env, env->namespace, Texts(def->name, "$$type")),
+ "){.length=sizeof(text)-1, .tag=TEXT_ASCII, .ascii=\"\" "
+ "text})\n"
+ "#define ",
+ namespace_name(env, env->namespace, Text$from_str(def->name)), "s(...) ((",
+ namespace_name(env, env->namespace, Texts(def->name, "$$type")),
+ ")Texts(__VA_ARGS__))\n"
+ "extern const TypeInfo_t ",
+ namespace_name(env, env->namespace, Texts(def->name, Text("$$info"))), ";\n");
}
case Extend: {
return EMPTY_TEXT;
}
- default:
- return EMPTY_TEXT;
+ default: return EMPTY_TEXT;
}
}
-Text_t compile_statement_namespace_header(env_t *env, Path_t header_path, ast_t *ast)
-{
+Text_t compile_statement_namespace_header(env_t *env, Path_t header_path, ast_t *ast) {
env_t *ns_env = NULL;
ast_t *block = NULL;
switch (ast->tag) {
@@ -4625,10 +4640,10 @@ Text_t compile_statement_namespace_header(env_t *env, Path_t header_path, ast_t
DeclareMatch(extend, ast, Extend);
ns_env = namespace_env(env, extend->name);
- env_t *extended = new(env_t);
+ env_t *extended = new (env_t);
*extended = *ns_env;
- extended->locals = new(Table_t, .fallback=env->locals);
- extended->namespace_bindings = new(Table_t, .fallback=env->namespace_bindings);
+ extended->locals = new (Table_t, .fallback = env->locals);
+ extended->namespace_bindings = new (Table_t, .fallback = env->namespace_bindings);
extended->id_suffix = env->id_suffix;
ns_env = extended;
@@ -4669,19 +4684,16 @@ Text_t compile_statement_namespace_header(env_t *env, Path_t header_path, ast_t
DeclareMatch(decl, ast, Declare);
const char *decl_name = Match(decl->var, Var)->name;
bool is_private = (decl_name[0] == '_');
- if (is_private)
- return EMPTY_TEXT;
+ if (is_private) return EMPTY_TEXT;
type_t *t = decl->type ? parse_type_ast(env, decl->type) : get_type(env, decl->value);
- if (t->tag == FunctionType)
- t = Type(ClosureType, t);
+ if (t->tag == FunctionType) t = Type(ClosureType, t);
assert(t->tag != ModuleType);
if (t->tag == AbortType || t->tag == VoidType || t->tag == ReturnType)
code_err(ast, "You can't declare a variable with a ", type_to_str(t), " value");
- return Texts(
- decl->value ? compile_statement_type_header(env, header_path, decl->value) : EMPTY_TEXT,
- "extern ", compile_declaration(t, namespace_name(env, env->namespace, Text$from_str(decl_name))), ";\n");
+ return Texts(decl->value ? compile_statement_type_header(env, header_path, decl->value) : EMPTY_TEXT, "extern ",
+ compile_declaration(t, namespace_name(env, env->namespace, Text$from_str(decl_name))), ";\n");
}
case FunctionDef: {
DeclareMatch(fndef, ast, FunctionDef);
@@ -4698,8 +4710,7 @@ Text_t compile_statement_namespace_header(env_t *env, Path_t header_path, ast_t
type_t *ret_t = fndef->ret_type ? parse_type_ast(env, fndef->ret_type) : Type(VoidType);
Text_t ret_type_code = compile_type(ret_t);
- if (ret_t->tag == AbortType)
- ret_type_code = Texts("__attribute__((noreturn)) _Noreturn ", ret_type_code);
+ if (ret_t->tag == AbortType) ret_type_code = Texts("__attribute__((noreturn)) _Noreturn ", ret_type_code);
Text_t name = namespace_name(env, env->namespace, Text$from_str(decl_name));
if (env->namespace && env->namespace->parent && env->namespace->name && streq(decl_name, env->namespace->name))
name = namespace_name(env, env->namespace, Text$from_str(String(get_line_number(ast->file, ast->start))));
@@ -4720,8 +4731,12 @@ Text_t compile_statement_namespace_header(env_t *env, Path_t header_path, ast_t
Text_t ret_type_code = compile_type(ret_t);
Text_t name = Text$from_str(get_type_name(ret_t));
if (name.length == 0)
- code_err(ast, "Conversions are only supported for text, struct, and enum types, not ", type_to_str(ret_t));
- Text_t name_code = namespace_name(env, env->namespace, Texts(name, "$", String(get_line_number(ast->file, ast->start))));
+ code_err(ast,
+ "Conversions are only supported for text, struct, and enum "
+ "types, not ",
+ type_to_str(ret_t));
+ Text_t name_code =
+ namespace_name(env, env->namespace, Texts(name, "$", String(get_line_number(ast->file, ast->start))));
return Texts(ret_type_code, " ", name_code, arg_signature, ";\n");
}
default: return EMPTY_TEXT;
@@ -4740,8 +4755,7 @@ typedef struct {
Path_t header_path;
} compile_typedef_info_t;
-static void _make_typedefs(compile_typedef_info_t *info, ast_t *ast)
-{
+static void _make_typedefs(compile_typedef_info_t *info, ast_t *ast) {
if (ast->tag == StructDef) {
DeclareMatch(def, ast, StructDef);
if (def->external) return;
@@ -4762,8 +4776,10 @@ static void _make_typedefs(compile_typedef_info_t *info, ast_t *ast)
for (tag_ast_t *tag = def->tags; tag; tag = tag->next) {
if (!tag->fields) continue;
- Text_t tag_struct = namespace_name(info->env, info->env->namespace, Texts(def->name, "$", tag->name, "$$struct"));
- Text_t tag_type = namespace_name(info->env, info->env->namespace, Texts(def->name, "$", tag->name, "$$type"));
+ Text_t tag_struct =
+ namespace_name(info->env, info->env->namespace, Texts(def->name, "$", tag->name, "$$struct"));
+ Text_t tag_type =
+ namespace_name(info->env, info->env->namespace, Texts(def->name, "$", tag->name, "$$type"));
*info->header = Texts(*info->header, "typedef struct ", tag_struct, " ", tag_type, ";\n");
}
} else {
@@ -4773,27 +4789,25 @@ static void _make_typedefs(compile_typedef_info_t *info, ast_t *ast)
}
} else if (ast->tag == LangDef) {
DeclareMatch(def, ast, LangDef);
- *info->header = Texts(*info->header, "typedef Text_t ", namespace_name(info->env, info->env->namespace, Texts(def->name, "$$type")), ";\n");
+ *info->header = Texts(*info->header, "typedef Text_t ",
+ namespace_name(info->env, info->env->namespace, Texts(def->name, "$$type")), ";\n");
}
}
-static void _define_types_and_funcs(compile_typedef_info_t *info, ast_t *ast)
-{
- *info->header = Texts(*info->header,
- compile_statement_type_header(info->env, info->header_path, ast),
- compile_statement_namespace_header(info->env, info->header_path, ast));
+static void _define_types_and_funcs(compile_typedef_info_t *info, ast_t *ast) {
+ *info->header = Texts(*info->header, compile_statement_type_header(info->env, info->header_path, ast),
+ compile_statement_namespace_header(info->env, info->header_path, ast));
}
-Text_t compile_file_header(env_t *env, Path_t header_path, ast_t *ast)
-{
- Text_t header = Texts(
- "#pragma once\n",
- env->do_source_mapping ? Texts("#line 1 ", quoted_str(ast->file->filename), "\n") : EMPTY_TEXT,
- "#include <tomo_"TOMO_VERSION"/tomo.h>\n");
+Text_t compile_file_header(env_t *env, Path_t header_path, ast_t *ast) {
+ Text_t header =
+ Texts("#pragma once\n",
+ env->do_source_mapping ? Texts("#line 1 ", quoted_str(ast->file->filename), "\n") : EMPTY_TEXT,
+ "#include <tomo_" TOMO_VERSION "/tomo.h>\n");
- compile_typedef_info_t info = {.env=env, .header=&header, .header_path=header_path};
- visit_topologically(Match(ast, Block)->statements, (Closure_t){.fn=(void*)_make_typedefs, &info});
- visit_topologically(Match(ast, Block)->statements, (Closure_t){.fn=(void*)_define_types_and_funcs, &info});
+ compile_typedef_info_t info = {.env = env, .header = &header, .header_path = header_path};
+ visit_topologically(Match(ast, Block)->statements, (Closure_t){.fn = (void *)_make_typedefs, &info});
+ visit_topologically(Match(ast, Block)->statements, (Closure_t){.fn = (void *)_define_types_and_funcs, &info});
header = Texts(header, "void ", namespace_name(env, env->namespace, Text("$initialize")), "(void);\n");
return header;
diff --git a/src/config.h b/src/config.h
index f7fa63a0..4c750f19 100644
--- a/src/config.h
+++ b/src/config.h
@@ -1,27 +1,27 @@
// Configuration of values that will be baked into the executable:
#ifndef TOMO_VERSION
-# define TOMO_VERSION "v???"
+#define TOMO_VERSION "v???"
#endif
#ifndef GIT_VERSION
-# define GIT_VERSION "???"
+#define GIT_VERSION "???"
#endif
#ifndef TOMO_PREFIX
-# define TOMO_PREFIX "/usr/local"
+#define TOMO_PREFIX "/usr/local"
#endif
#ifndef DEFAULT_C_COMPILER
-# define DEFAULT_C_COMPILER "cc"
+#define DEFAULT_C_COMPILER "cc"
#endif
#ifndef SUDO
-# if defined(__OpenBSD__)
-# define SUDO "doas"
-# else
-# define SUDO "sudo"
-# endif
+#if defined(__OpenBSD__)
+#define SUDO "doas"
+#else
+#define SUDO "sudo"
+#endif
#endif
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/enums.c b/src/enums.c
index dba6d4cb..078600e0 100644
--- a/src/enums.c
+++ b/src/enums.c
@@ -11,8 +11,7 @@
#include "structs.h"
#include "typecheck.h"
-Text_t compile_enum_typeinfo(env_t *env, ast_t *ast)
-{
+Text_t compile_enum_typeinfo(env_t *env, ast_t *ast) {
DeclareMatch(def, ast, EnumDef);
// Compile member types and constructors:
@@ -23,8 +22,8 @@ Text_t compile_enum_typeinfo(env_t *env, ast_t *ast)
const char *tag_name = String(def->name, "$", tag->name);
type_t *tag_type = Table$str_get(*env->types, tag_name);
assert(tag_type && tag_type->tag == StructType);
- member_typeinfos = Texts(
- member_typeinfos, compile_struct_typeinfo(env, tag_type, tag_name, tag->fields, tag->secret, false));
+ member_typeinfos =
+ Texts(member_typeinfos, compile_struct_typeinfo(env, tag_type, tag_name, tag->fields, tag->secret, false));
}
int num_tags = 0;
@@ -34,25 +33,25 @@ Text_t compile_enum_typeinfo(env_t *env, ast_t *ast)
type_t *t = Table$str_get(*env->types, def->name);
const char *metamethods = is_packed_data(t) ? "PackedDataEnum$metamethods" : "Enum$metamethods";
Text_t info = namespace_name(env, env->namespace, Texts(def->name, "$$info"));
- Text_t typeinfo = Texts("public const TypeInfo_t ", info, " = {",
- String((int64_t)type_size(t)), "u, ", String((int64_t)type_align(t)), "u, .metamethods=", metamethods,
- ", {.tag=EnumInfo, .EnumInfo={.name=\"", def->name, "\", "
- ".num_tags=", String((int64_t)num_tags), ", .tags=(NamedType_t[]){");
+ Text_t typeinfo = Texts("public const TypeInfo_t ", info, " = {", String((int64_t)type_size(t)), "u, ",
+ String((int64_t)type_align(t)), "u, .metamethods=", metamethods,
+ ", {.tag=EnumInfo, .EnumInfo={.name=\"", def->name,
+ "\", "
+ ".num_tags=",
+ String((int64_t)num_tags), ", .tags=(NamedType_t[]){");
for (tag_ast_t *tag = def->tags; tag; tag = tag->next) {
const char *tag_type_name = String(def->name, "$", tag->name);
type_t *tag_type = Table$str_get(*env->types, tag_type_name);
if (tag_type && Match(tag_type, StructType)->fields)
typeinfo = Texts(typeinfo, "{\"", tag->name, "\", ", compile_type_info(tag_type), "}, ");
- else
- typeinfo = Texts(typeinfo, "{\"", tag->name, "\"}, ");
+ else typeinfo = Texts(typeinfo, "{\"", tag->name, "\"}, ");
}
typeinfo = Texts(typeinfo, "}}}};\n");
return Texts(member_typeinfos, typeinfo);
}
-Text_t compile_enum_constructors(env_t *env, ast_t *ast)
-{
+Text_t compile_enum_constructors(env_t *env, ast_t *ast) {
DeclareMatch(def, ast, EnumDef);
Text_t constructors = EMPTY_TEXT;
for (tag_ast_t *tag = def->tags; tag; tag = tag->next) {
@@ -69,7 +68,7 @@ Text_t compile_enum_constructors(env_t *env, ast_t *ast)
Text_t tagged_name = namespace_name(env, env->namespace, Texts(def->name, "$tagged$", tag->name));
Text_t tag_name = namespace_name(env, env->namespace, Texts(def->name, "$tag$", tag->name));
Text_t constructor_impl = Texts("public inline ", type_name, " ", tagged_name, "(", arg_sig, ") { return (",
- type_name, "){.$tag=", tag_name, ", .", valid_c_name(tag->name), "={");
+ type_name, "){.$tag=", tag_name, ", .", valid_c_name(tag->name), "={");
for (arg_ast_t *field = tag->fields; field; field = field->next) {
constructor_impl = Texts(constructor_impl, "$", field->name);
if (field->next) constructor_impl = Texts(constructor_impl, ", ");
@@ -80,8 +79,7 @@ Text_t compile_enum_constructors(env_t *env, ast_t *ast)
return constructors;
}
-Text_t compile_enum_header(env_t *env, ast_t *ast)
-{
+Text_t compile_enum_header(env_t *env, ast_t *ast) {
DeclareMatch(def, ast, EnumDef);
Text_t all_defs = EMPTY_TEXT;
Text_t none_name = namespace_name(env, env->namespace, Texts(def->name, "$none"));
@@ -104,13 +102,17 @@ Text_t compile_enum_header(env_t *env, ast_t *ast)
}
Text_t struct_name = namespace_name(env, env->namespace, Texts(def->name, "$$struct"));
- Text_t enum_def = Texts("struct ", struct_name, " {\n"
- "enum ", enum_tags, " $tag;\n"
- "union {\n");
+ Text_t enum_def = Texts("struct ", struct_name,
+ " {\n"
+ "enum ",
+ enum_tags,
+ " $tag;\n"
+ "union {\n");
for (tag_ast_t *tag = def->tags; tag; tag = tag->next) {
if (!tag->fields) continue;
Text_t field_def = compile_struct_header(
- env, WrapAST(ast, StructDef, .name=Text$as_c_string(Texts(def->name, "$", tag->name)), .fields=tag->fields));
+ env,
+ WrapAST(ast, StructDef, .name = Text$as_c_string(Texts(def->name, "$", tag->name)), .fields = tag->fields));
all_defs = Texts(all_defs, field_def);
Text_t tag_type = namespace_name(env, env->namespace, Texts(def->name, "$", tag->name, "$$type"));
enum_def = Texts(enum_def, tag_type, " ", valid_c_name(tag->name), ";\n");
diff --git a/src/environment.c b/src/environment.c
index 22b13e65..3b3c6d0b 100644
--- a/src/environment.c
+++ b/src/environment.c
@@ -13,16 +13,17 @@
#include "typecheck.h"
type_t *TEXT_TYPE = NULL;
-public type_t *PATH_TYPE = NULL;
-public type_t *PATH_TYPE_TYPE = NULL;
+public
+type_t *PATH_TYPE = NULL;
+public
+type_t *PATH_TYPE_TYPE = NULL;
-static type_t *declare_type(env_t *env, const char *def_str)
-{
+static type_t *declare_type(env_t *env, const char *def_str) {
ast_t *ast = parse(def_str);
- if (!ast) errx(1, "Couldn't not parse struct def: %s", def_str);
- if (ast->tag != Block) errx(1, "Couldn't not parse struct def: %s", def_str);
+ if (!ast) errx(1, "Couldn't not parse struct def: %s", def_str);
+ if (ast->tag != Block) errx(1, "Couldn't not parse struct def: %s", def_str);
ast_list_t *statements = Match(ast, Block)->statements;
- if (statements == NULL || statements->next) errx(1, "Couldn't not parse struct def: %s", def_str);
+ if (statements == NULL || statements->next) errx(1, "Couldn't not parse struct def: %s", def_str);
switch (statements->ast->tag) {
case StructDef: {
DeclareMatch(def, statements->ast, StructDef);
@@ -41,30 +42,27 @@ static type_t *declare_type(env_t *env, const char *def_str)
return NULL;
}
-static type_t *bind_type(env_t *env, const char *name, type_t *type)
-{
- if (Table$str_get(*env->types, name))
- errx(1, "Duplicate binding for type: %s", name);
+static type_t *bind_type(env_t *env, const char *name, type_t *type) {
+ if (Table$str_get(*env->types, name)) errx(1, "Duplicate binding for type: %s", name);
Table$str_set(env->types, name, type);
return type;
}
-env_t *global_env(bool source_mapping)
-{
+env_t *global_env(bool source_mapping) {
static env_t *_global_env = NULL;
if (_global_env != NULL) return _global_env;
- env_t *env = new(env_t);
- env->code = new(compilation_unit_t);
- env->types = new(Table_t);
- env->globals = new(Table_t);
+ env_t *env = new (env_t);
+ env->code = new (compilation_unit_t);
+ env->types = new (Table_t);
+ env->globals = new (Table_t);
env->locals = env->globals;
- env->imports = new(Table_t);
+ env->imports = new (Table_t);
env->do_source_mapping = source_mapping;
- TEXT_TYPE = bind_type(env, "Text", Type(TextType, .lang="Text", .env=namespace_env(env, "Text")));
+ TEXT_TYPE = bind_type(env, "Text", Type(TextType, .lang = "Text", .env = namespace_env(env, "Text")));
(void)bind_type(env, "Int", Type(BigIntType));
- (void)bind_type(env, "Int32", Type(IntType, .bits=TYPE_IBITS32));
+ (void)bind_type(env, "Int32", Type(IntType, .bits = TYPE_IBITS32));
(void)bind_type(env, "Memory", Type(MemoryType));
PATH_TYPE_TYPE = declare_type(env, "enum PathType(Relative, Absolute, Home)");
PATH_TYPE = declare_type(env, "struct Path(type:PathType, components:[Text])");
@@ -83,331 +81,289 @@ env_t *global_env(bool source_mapping)
{"Void", Type(VoidType), Text("Void_t"), Text("Void$info"), {}},
{"Abort", Type(AbortType), Text("void"), Text("Abort$info"), {}},
{"Memory", Type(MemoryType), Text("Memory_t"), Text("Memory$info"), {}},
- {"Bool", Type(BoolType), Text("Bool_t"), Text("Bool$info"), TypedList(ns_entry_t,
- {"parse", "Bool$parse", "func(text:Text, remainder:&Text? = none -> Bool?)"},
- )},
- {"Byte", Type(ByteType), Text("Byte_t"), Text("Byte$info"), TypedList(ns_entry_t,
- {"get_bit", "Byte$get_bit", "func(x:Byte, bit_index:Int -> Bool)"},
- {"hex", "Byte$hex", "func(byte:Byte, uppercase=yes, prefix=no -> Text)"},
- {"is_between", "Byte$is_between", "func(x:Byte, low:Byte, high:Byte -> Bool)"},
- {"max", "Byte$max", "Byte"},
- {"min", "Byte$min", "Byte"},
- {"parse", "Byte$parse", "func(text:Text, remainder:&Text? = none -> Byte?)"},
- {"to", "Byte$to", "func(first:Byte, last:Byte, step:Int8?=none -> func(->Byte?))"},
- )},
- {"Int", Type(BigIntType), Text("Int_t"), Text("Int$info"), TypedList(ns_entry_t,
- {"abs", "Int$abs", "func(x:Int -> Int)"},
- {"bit_and", "Int$bit_and", "func(x,y:Int -> Int)"},
- {"bit_or", "Int$bit_or", "func(x,y:Int -> Int)"},
- {"bit_xor", "Int$bit_xor", "func(x,y:Int -> Int)"},
- {"choose", "Int$choose", "func(x,y:Int -> Int)"},
- {"clamped", "Int$clamped", "func(x,low,high:Int -> Int)"},
- {"divided_by", "Int$divided_by", "func(x,y:Int -> Int)"},
- {"factorial", "Int$factorial", "func(x:Int -> Int)"},
- {"gcd", "Int$gcd", "func(x,y:Int -> Int)"},
- {"get_bit", "Int$get_bit", "func(x,bit_index:Int -> Bool)"},
- {"hex", "Int$hex", "func(i:Int, digits=0, uppercase=yes, prefix=yes -> Text)"},
- {"is_between", "Int$is_between", "func(x:Int,low:Int,high:Int -> Bool)"},
- {"is_prime", "Int$is_prime", "func(x:Int,reps=50 -> Bool)"},
- {"left_shifted", "Int$left_shifted", "func(x,y:Int -> Int)"},
- {"minus", "Int$minus", "func(x,y:Int -> Int)"},
- {"modulo", "Int$modulo", "func(x,y:Int -> Int)"},
- {"modulo1", "Int$modulo1", "func(x,y:Int -> Int)"},
- {"negated", "Int$negated", "func(x:Int -> Int)"},
- {"negative", "Int$negative", "func(x:Int -> Int)"},
- {"next_prime", "Int$next_prime", "func(x:Int -> Int)"},
- {"octal", "Int$octal", "func(i:Int, digits=0, prefix=yes -> Text)"},
- {"onward", "Int$onward", "func(first:Int,step=1 -> func(->Int?))"},
- {"parse", "Int$parse", "func(text:Text, remainder:&Text? = none -> Int?)"},
- {"plus", "Int$plus", "func(x,y:Int -> Int)"},
- {"power", "Int$power", "func(base:Int,exponent:Int -> Int)"},
+ {"Bool", Type(BoolType), Text("Bool_t"), Text("Bool$info"),
+ TypedList(ns_entry_t, {"parse", "Bool$parse", "func(text:Text, remainder:&Text? = none -> Bool?)"}, )},
+ {"Byte", Type(ByteType), Text("Byte_t"), Text("Byte$info"),
+ TypedList(ns_entry_t, {"get_bit", "Byte$get_bit", "func(x:Byte, bit_index:Int -> Bool)"},
+ {"hex", "Byte$hex", "func(byte:Byte, uppercase=yes, prefix=no -> Text)"},
+ {"is_between", "Byte$is_between", "func(x:Byte, low:Byte, high:Byte -> Bool)"},
+ {"max", "Byte$max", "Byte"}, {"min", "Byte$min", "Byte"},
+ {"parse", "Byte$parse", "func(text:Text, remainder:&Text? = none -> Byte?)"},
+ {"to", "Byte$to", "func(first:Byte, last:Byte, step:Int8?=none -> func(->Byte?))"}, )},
+ {"Int", Type(BigIntType), Text("Int_t"), Text("Int$info"),
+ TypedList(
+ ns_entry_t, {"abs", "Int$abs", "func(x:Int -> Int)"}, {"bit_and", "Int$bit_and", "func(x,y:Int -> Int)"},
+ {"bit_or", "Int$bit_or", "func(x,y:Int -> Int)"}, {"bit_xor", "Int$bit_xor", "func(x,y:Int -> Int)"},
+ {"choose", "Int$choose", "func(x,y:Int -> Int)"},
+ {"clamped", "Int$clamped", "func(x,low,high:Int -> Int)"},
+ {"divided_by", "Int$divided_by", "func(x,y:Int -> Int)"},
+ {"factorial", "Int$factorial", "func(x:Int -> Int)"}, {"gcd", "Int$gcd", "func(x,y:Int -> Int)"},
+ {"get_bit", "Int$get_bit", "func(x,bit_index:Int -> Bool)"},
+ {"hex", "Int$hex", "func(i:Int, digits=0, uppercase=yes, prefix=yes -> Text)"},
+ {"is_between", "Int$is_between", "func(x:Int,low:Int,high:Int -> Bool)"},
+ {"is_prime", "Int$is_prime", "func(x:Int,reps=50 -> Bool)"},
+ {"left_shifted", "Int$left_shifted", "func(x,y:Int -> Int)"},
+ {"minus", "Int$minus", "func(x,y:Int -> Int)"}, {"modulo", "Int$modulo", "func(x,y:Int -> Int)"},
+ {"modulo1", "Int$modulo1", "func(x,y:Int -> Int)"}, {"negated", "Int$negated", "func(x:Int -> Int)"},
+ {"negative", "Int$negative", "func(x:Int -> Int)"}, {"next_prime", "Int$next_prime", "func(x:Int -> Int)"},
+ {"octal", "Int$octal", "func(i:Int, digits=0, prefix=yes -> Text)"},
+ {"onward", "Int$onward", "func(first:Int,step=1 -> func(->Int?))"},
+ {"parse", "Int$parse", "func(text:Text, remainder:&Text? = none -> Int?)"},
+ {"plus", "Int$plus", "func(x,y:Int -> Int)"}, {"power", "Int$power", "func(base:Int,exponent:Int -> Int)"},
#if __GNU_MP_VERSION >= 6
#if __GNU_MP_VERSION_MINOR >= 3
- {"prev_prime", "Int$prev_prime", "func(x:Int -> Int?)"},
+ {"prev_prime", "Int$prev_prime", "func(x:Int -> Int?)"},
#endif
#endif
- {"right_shifted", "Int$right_shifted", "func(x,y:Int -> Int)"},
- {"sqrt", "Int$sqrt", "func(x:Int -> Int?)"},
- {"times", "Int$times", "func(x,y:Int -> Int)"},
- {"to", "Int$to", "func(first:Int,last:Int,step:Int?=none -> func(->Int?))"},
- )},
- {"Int64", Type(IntType, .bits=TYPE_IBITS64), Text("Int64_t"), Text("Int64$info"), TypedList(ns_entry_t,
- {"abs", "labs", "func(i:Int64 -> Int64)"},
- {"bits", "Int64$bits", "func(x:Int64 -> [Bool])"},
- {"clamped", "Int64$clamped", "func(x,low,high:Int64 -> Int64)"},
- {"divided_by", "Int64$divided_by", "func(x,y:Int64 -> Int64)"},
- {"gcd", "Int64$gcd", "func(x,y:Int64 -> Int64)"},
- {"parse", "Int64$parse", "func(text:Text, remainder:&Text? = none -> Int64?)"},
- {"get_bit", "Int64$get_bit", "func(x:Int64, bit_index:Int -> Bool)"},
- {"hex", "Int64$hex", "func(i:Int64, digits=0, uppercase=yes, prefix=yes -> Text)"},
- {"is_between", "Int64$is_between", "func(x:Int64,low:Int64,high:Int64 -> Bool)"},
- {"max", "Int64$max", "Int64"},
- {"min", "Int64$min", "Int64"},
- {"modulo", "Int64$modulo", "func(x,y:Int64 -> Int64)"},
- {"modulo1", "Int64$modulo1", "func(x,y:Int64 -> Int64)"},
- {"octal", "Int64$octal", "func(i:Int64, digits=0, prefix=yes -> Text)"},
- {"onward", "Int64$onward", "func(first:Int64,step=Int64(1) -> func(->Int64?))"},
- {"to", "Int64$to", "func(first:Int64,last:Int64,step:Int64?=none -> func(->Int64?))"},
- {"unsigned_left_shifted", "Int64$unsigned_left_shifted", "func(x:Int64,y:Int64 -> Int64)"},
- {"unsigned_right_shifted", "Int64$unsigned_right_shifted", "func(x:Int64,y:Int64 -> Int64)"},
- {"wrapping_minus", "Int64$wrapping_minus", "func(x:Int64,y:Int64 -> Int64)"},
- {"wrapping_plus", "Int64$wrapping_plus", "func(x:Int64,y:Int64 -> Int64)"},
- )},
- {"Int32", Type(IntType, .bits=TYPE_IBITS32), Text("Int32_t"), Text("Int32$info"), TypedList(ns_entry_t,
- {"abs", "abs", "func(i:Int32 -> Int32)"},
- {"bits", "Int32$bits", "func(x:Int32 -> [Bool])"},
- {"clamped", "Int32$clamped", "func(x,low,high:Int32 -> Int32)"},
- {"divided_by", "Int32$divided_by", "func(x,y:Int32 -> Int32)"},
- {"gcd", "Int32$gcd", "func(x,y:Int32 -> Int32)"},
- {"parse", "Int32$parse", "func(text:Text, remainder:&Text? = none -> Int32?)"},
- {"get_bit", "Int32$get_bit", "func(x:Int32, bit_index:Int -> Bool)"},
- {"hex", "Int32$hex", "func(i:Int32, digits=0, uppercase=yes, prefix=yes -> Text)"},
- {"is_between", "Int32$is_between", "func(x:Int32,low:Int32,high:Int32 -> Bool)"},
- {"max", "Int32$max", "Int32"},
- {"min", "Int32$min", "Int32"},
- {"modulo", "Int32$modulo", "func(x,y:Int32 -> Int32)"},
- {"modulo1", "Int32$modulo1", "func(x,y:Int32 -> Int32)"},
- {"octal", "Int32$octal", "func(i:Int32, digits=0, prefix=yes -> Text)"},
- {"onward", "Int32$onward", "func(first:Int32,step=Int32(1) -> func(->Int32?))"},
- {"to", "Int32$to", "func(first:Int32,last:Int32,step:Int32?=none -> func(->Int32?))"},
- {"unsigned_left_shifted", "Int32$unsigned_left_shifted", "func(x:Int32,y:Int32 -> Int32)"},
- {"unsigned_right_shifted", "Int32$unsigned_right_shifted", "func(x:Int32,y:Int32 -> Int32)"},
- {"wrapping_minus", "Int32$wrapping_minus", "func(x:Int32,y:Int32 -> Int32)"},
- {"wrapping_plus", "Int32$wrapping_plus", "func(x:Int32,y:Int32 -> Int32)"},
- )},
- {"Int16", Type(IntType, .bits=TYPE_IBITS16), Text("Int16_t"), Text("Int16$info"), TypedList(ns_entry_t,
- {"abs", "abs", "func(i:Int16 -> Int16)"},
- {"bits", "Int16$bits", "func(x:Int16 -> [Bool])"},
- {"clamped", "Int16$clamped", "func(x,low,high:Int16 -> Int16)"},
- {"divided_by", "Int16$divided_by", "func(x,y:Int16 -> Int16)"},
- {"gcd", "Int16$gcd", "func(x,y:Int16 -> Int16)"},
- {"parse", "Int16$parse", "func(text:Text, remainder:&Text? = none -> Int16?)"},
- {"get_bit", "Int16$get_bit", "func(x:Int16, bit_index:Int -> Bool)"},
- {"hex", "Int16$hex", "func(i:Int16, digits=0, uppercase=yes, prefix=yes -> Text)"},
- {"is_between", "Int16$is_between", "func(x:Int16,low:Int16,high:Int16 -> Bool)"},
- {"max", "Int16$max", "Int16"},
- {"min", "Int16$min", "Int16"},
- {"modulo", "Int16$modulo", "func(x,y:Int16 -> Int16)"},
- {"modulo1", "Int16$modulo1", "func(x,y:Int16 -> Int16)"},
- {"octal", "Int16$octal", "func(i:Int16, digits=0, prefix=yes -> Text)"},
- {"onward", "Int16$onward", "func(first:Int16,step=Int16(1) -> func(->Int16?))"},
- {"to", "Int16$to", "func(first:Int16,last:Int16,step:Int16?=none -> func(->Int16?))"},
- {"unsigned_left_shifted", "Int16$unsigned_left_shifted", "func(x:Int16,y:Int16 -> Int16)"},
- {"unsigned_right_shifted", "Int16$unsigned_right_shifted", "func(x:Int16,y:Int16 -> Int16)"},
- {"wrapping_minus", "Int16$wrapping_minus", "func(x:Int16,y:Int16 -> Int16)"},
- {"wrapping_plus", "Int16$wrapping_plus", "func(x:Int16,y:Int16 -> Int16)"},
- )},
- {"Int8", Type(IntType, .bits=TYPE_IBITS8), Text("Int8_t"), Text("Int8$info"), TypedList(ns_entry_t,
- {"abs", "abs", "func(i:Int8 -> Int8)"},
- {"bits", "Int8$bits", "func(x:Int8 -> [Bool])"},
- {"clamped", "Int8$clamped", "func(x,low,high:Int8 -> Int8)"},
- {"divided_by", "Int8$divided_by", "func(x,y:Int8 -> Int8)"},
- {"gcd", "Int8$gcd", "func(x,y:Int8 -> Int8)"},
- {"parse", "Int8$parse", "func(text:Text, remainder:&Text? = none -> Int8?)"},
- {"get_bit", "Int8$get_bit", "func(x:Int8, bit_index:Int -> Bool)"},
- {"hex", "Int8$hex", "func(i:Int8, digits=0, uppercase=yes, prefix=yes -> Text)"},
- {"is_between", "Int8$is_between", "func(x:Int8,low:Int8,high:Int8 -> Bool)"},
- {"max", "Int8$max", "Int8"},
- {"min", "Int8$min", "Int8"},
- {"modulo", "Int8$modulo", "func(x,y:Int8 -> Int8)"},
- {"modulo1", "Int8$modulo1", "func(x,y:Int8 -> Int8)"},
- {"octal", "Int8$octal", "func(i:Int8, digits=0, prefix=yes -> Text)"},
- {"onward", "Int8$onward", "func(first:Int8,step=Int8(1) -> func(->Int8?))"},
- {"to", "Int8$to", "func(first:Int8,last:Int8,step:Int8?=none -> func(->Int8?))"},
- {"unsigned_left_shifted", "Int8$unsigned_left_shifted", "func(x:Int8,y:Int8 -> Int8)"},
- {"unsigned_right_shifted", "Int8$unsigned_right_shifted", "func(x:Int8,y:Int8 -> Int8)"},
- {"wrapping_minus", "Int8$wrapping_minus", "func(x:Int8,y:Int8 -> Int8)"},
- {"wrapping_plus", "Int8$wrapping_plus", "func(x:Int8,y:Int8 -> Int8)"},
- )},
-#define C(name) {#name, "M_"#name, "Num"}
+ {"right_shifted", "Int$right_shifted", "func(x,y:Int -> Int)"},
+ {"sqrt", "Int$sqrt", "func(x:Int -> Int?)"}, {"times", "Int$times", "func(x,y:Int -> Int)"},
+ {"to", "Int$to", "func(first:Int,last:Int,step:Int?=none -> func(->Int?))"}, )},
+ {"Int64", Type(IntType, .bits = TYPE_IBITS64), Text("Int64_t"), Text("Int64$info"),
+ TypedList(ns_entry_t, {"abs", "labs", "func(i:Int64 -> Int64)"},
+ {"bits", "Int64$bits", "func(x:Int64 -> [Bool])"},
+ {"clamped", "Int64$clamped", "func(x,low,high:Int64 -> Int64)"},
+ {"divided_by", "Int64$divided_by", "func(x,y:Int64 -> Int64)"},
+ {"gcd", "Int64$gcd", "func(x,y:Int64 -> Int64)"},
+ {"parse", "Int64$parse", "func(text:Text, remainder:&Text? = none -> Int64?)"},
+ {"get_bit", "Int64$get_bit", "func(x:Int64, bit_index:Int -> Bool)"},
+ {"hex", "Int64$hex", "func(i:Int64, digits=0, uppercase=yes, prefix=yes -> Text)"},
+ {"is_between", "Int64$is_between", "func(x:Int64,low:Int64,high:Int64 -> Bool)"},
+ {"max", "Int64$max", "Int64"}, {"min", "Int64$min", "Int64"},
+ {"modulo", "Int64$modulo", "func(x,y:Int64 -> Int64)"},
+ {"modulo1", "Int64$modulo1", "func(x,y:Int64 -> Int64)"},
+ {"octal", "Int64$octal", "func(i:Int64, digits=0, prefix=yes -> Text)"},
+ {"onward", "Int64$onward", "func(first:Int64,step=Int64(1) -> func(->Int64?))"},
+ {"to", "Int64$to", "func(first:Int64,last:Int64,step:Int64?=none -> func(->Int64?))"},
+ {"unsigned_left_shifted", "Int64$unsigned_left_shifted", "func(x:Int64,y:Int64 -> Int64)"},
+ {"unsigned_right_shifted", "Int64$unsigned_right_shifted", "func(x:Int64,y:Int64 -> Int64)"},
+ {"wrapping_minus", "Int64$wrapping_minus", "func(x:Int64,y:Int64 -> Int64)"},
+ {"wrapping_plus", "Int64$wrapping_plus", "func(x:Int64,y:Int64 -> Int64)"}, )},
+ {"Int32", Type(IntType, .bits = TYPE_IBITS32), Text("Int32_t"), Text("Int32$info"),
+ TypedList(ns_entry_t, {"abs", "abs", "func(i:Int32 -> Int32)"},
+ {"bits", "Int32$bits", "func(x:Int32 -> [Bool])"},
+ {"clamped", "Int32$clamped", "func(x,low,high:Int32 -> Int32)"},
+ {"divided_by", "Int32$divided_by", "func(x,y:Int32 -> Int32)"},
+ {"gcd", "Int32$gcd", "func(x,y:Int32 -> Int32)"},
+ {"parse", "Int32$parse", "func(text:Text, remainder:&Text? = none -> Int32?)"},
+ {"get_bit", "Int32$get_bit", "func(x:Int32, bit_index:Int -> Bool)"},
+ {"hex", "Int32$hex", "func(i:Int32, digits=0, uppercase=yes, prefix=yes -> Text)"},
+ {"is_between", "Int32$is_between", "func(x:Int32,low:Int32,high:Int32 -> Bool)"},
+ {"max", "Int32$max", "Int32"}, {"min", "Int32$min", "Int32"},
+ {"modulo", "Int32$modulo", "func(x,y:Int32 -> Int32)"},
+ {"modulo1", "Int32$modulo1", "func(x,y:Int32 -> Int32)"},
+ {"octal", "Int32$octal", "func(i:Int32, digits=0, prefix=yes -> Text)"},
+ {"onward", "Int32$onward", "func(first:Int32,step=Int32(1) -> func(->Int32?))"},
+ {"to", "Int32$to", "func(first:Int32,last:Int32,step:Int32?=none -> func(->Int32?))"},
+ {"unsigned_left_shifted", "Int32$unsigned_left_shifted", "func(x:Int32,y:Int32 -> Int32)"},
+ {"unsigned_right_shifted", "Int32$unsigned_right_shifted", "func(x:Int32,y:Int32 -> Int32)"},
+ {"wrapping_minus", "Int32$wrapping_minus", "func(x:Int32,y:Int32 -> Int32)"},
+ {"wrapping_plus", "Int32$wrapping_plus", "func(x:Int32,y:Int32 -> Int32)"}, )},
+ {"Int16", Type(IntType, .bits = TYPE_IBITS16), Text("Int16_t"), Text("Int16$info"),
+ TypedList(ns_entry_t, {"abs", "abs", "func(i:Int16 -> Int16)"},
+ {"bits", "Int16$bits", "func(x:Int16 -> [Bool])"},
+ {"clamped", "Int16$clamped", "func(x,low,high:Int16 -> Int16)"},
+ {"divided_by", "Int16$divided_by", "func(x,y:Int16 -> Int16)"},
+ {"gcd", "Int16$gcd", "func(x,y:Int16 -> Int16)"},
+ {"parse", "Int16$parse", "func(text:Text, remainder:&Text? = none -> Int16?)"},
+ {"get_bit", "Int16$get_bit", "func(x:Int16, bit_index:Int -> Bool)"},
+ {"hex", "Int16$hex", "func(i:Int16, digits=0, uppercase=yes, prefix=yes -> Text)"},
+ {"is_between", "Int16$is_between", "func(x:Int16,low:Int16,high:Int16 -> Bool)"},
+ {"max", "Int16$max", "Int16"}, {"min", "Int16$min", "Int16"},
+ {"modulo", "Int16$modulo", "func(x,y:Int16 -> Int16)"},
+ {"modulo1", "Int16$modulo1", "func(x,y:Int16 -> Int16)"},
+ {"octal", "Int16$octal", "func(i:Int16, digits=0, prefix=yes -> Text)"},
+ {"onward", "Int16$onward", "func(first:Int16,step=Int16(1) -> func(->Int16?))"},
+ {"to", "Int16$to", "func(first:Int16,last:Int16,step:Int16?=none -> func(->Int16?))"},
+ {"unsigned_left_shifted", "Int16$unsigned_left_shifted", "func(x:Int16,y:Int16 -> Int16)"},
+ {"unsigned_right_shifted", "Int16$unsigned_right_shifted", "func(x:Int16,y:Int16 -> Int16)"},
+ {"wrapping_minus", "Int16$wrapping_minus", "func(x:Int16,y:Int16 -> Int16)"},
+ {"wrapping_plus", "Int16$wrapping_plus", "func(x:Int16,y:Int16 -> Int16)"}, )},
+ {"Int8", Type(IntType, .bits = TYPE_IBITS8), Text("Int8_t"), Text("Int8$info"),
+ TypedList(
+ ns_entry_t, {"abs", "abs", "func(i:Int8 -> Int8)"}, {"bits", "Int8$bits", "func(x:Int8 -> [Bool])"},
+ {"clamped", "Int8$clamped", "func(x,low,high:Int8 -> Int8)"},
+ {"divided_by", "Int8$divided_by", "func(x,y:Int8 -> Int8)"}, {"gcd", "Int8$gcd", "func(x,y:Int8 -> Int8)"},
+ {"parse", "Int8$parse", "func(text:Text, remainder:&Text? = none -> Int8?)"},
+ {"get_bit", "Int8$get_bit", "func(x:Int8, bit_index:Int -> Bool)"},
+ {"hex", "Int8$hex", "func(i:Int8, digits=0, uppercase=yes, prefix=yes -> Text)"},
+ {"is_between", "Int8$is_between", "func(x:Int8,low:Int8,high:Int8 -> Bool)"}, {"max", "Int8$max", "Int8"},
+ {"min", "Int8$min", "Int8"}, {"modulo", "Int8$modulo", "func(x,y:Int8 -> Int8)"},
+ {"modulo1", "Int8$modulo1", "func(x,y:Int8 -> Int8)"},
+ {"octal", "Int8$octal", "func(i:Int8, digits=0, prefix=yes -> Text)"},
+ {"onward", "Int8$onward", "func(first:Int8,step=Int8(1) -> func(->Int8?))"},
+ {"to", "Int8$to", "func(first:Int8,last:Int8,step:Int8?=none -> func(->Int8?))"},
+ {"unsigned_left_shifted", "Int8$unsigned_left_shifted", "func(x:Int8,y:Int8 -> Int8)"},
+ {"unsigned_right_shifted", "Int8$unsigned_right_shifted", "func(x:Int8,y:Int8 -> Int8)"},
+ {"wrapping_minus", "Int8$wrapping_minus", "func(x:Int8,y:Int8 -> Int8)"},
+ {"wrapping_plus", "Int8$wrapping_plus", "func(x:Int8,y:Int8 -> Int8)"}, )},
+#define C(name) {#name, "M_" #name, "Num"}
#define F(name) {#name, #name, "func(n:Num -> Num)"}
#define F_opt(name) {#name, #name, "func(n:Num -> Num?)"}
#define F2(name) {#name, #name, "func(x,y:Num -> Num)"}
- {"Num", Type(NumType, .bits=TYPE_NBITS64), Text("Num_t"), Text("Num$info"), TypedList(ns_entry_t,
- {"near", "Num$near", "func(x,y:Num, ratio=1e-9, min_epsilon=1e-9 -> Bool)"},
- {"clamped", "Num$clamped", "func(x,low,high:Num -> Num)"},
- {"percent", "Num$percent", "func(n:Num,precision=0.01 -> Text)"},
- {"with_precision", "Num$with_precision", "func(n:Num,precision:Num -> Num)"},
- {"is_between", "Num$is_between", "func(x:Num,low:Num,high:Num -> Bool)"},
- {"isinf", "Num$isinf", "func(n:Num -> Bool)"},
- {"isfinite", "Num$isfinite", "func(n:Num -> Bool)"},
- {"modulo", "Num$mod", "func(x,y:Num -> Num)"},
- {"modulo1", "Num$mod1", "func(x,y:Num -> Num)"},
- C(2_SQRTPI), C(E), C(PI_2), C(2_PI), C(1_PI), C(LN10), C(LN2), C(LOG2E),
- C(PI), C(PI_4), C(SQRT2), C(SQRT1_2),
- {"INF", "(Num_t)(INFINITY)", "Num"},
- {"TAU", "(Num_t)(2.*M_PI)", "Num"},
- {"mix", "Num$mix", "func(amount,x,y:Num -> Num)"},
- {"parse", "Num$parse", "func(text:Text, remainder:&Text? = none -> Num?)"},
- {"abs", "fabs", "func(n:Num -> Num)"},
- F_opt(acos), F_opt(acosh), F_opt(asin), F(asinh), F(atan), F_opt(atanh),
- F(cbrt), F(ceil), F_opt(cos), F(cosh), F(erf), F(erfc),
- F(exp), F(exp2), F(expm1), F(floor), F(j0), F(j1), F_opt(log), F_opt(log10), F_opt(log1p),
- F_opt(log2), F(logb), F(rint), F(round), F(significand), F_opt(sin), F(sinh), F_opt(sqrt),
- F_opt(tan), F(tanh), F_opt(tgamma), F(trunc), F_opt(y0), F_opt(y1),
- F2(atan2), F2(copysign), F2(fdim), F2(hypot), F2(nextafter),
- )},
+ {"Num", Type(NumType, .bits = TYPE_NBITS64), Text("Num_t"), Text("Num$info"),
+ TypedList(ns_entry_t, {"near", "Num$near", "func(x,y:Num, ratio=1e-9, min_epsilon=1e-9 -> Bool)"},
+ {"clamped", "Num$clamped", "func(x,low,high:Num -> Num)"},
+ {"percent", "Num$percent", "func(n:Num,precision=0.01 -> Text)"},
+ {"with_precision", "Num$with_precision", "func(n:Num,precision:Num -> Num)"},
+ {"is_between", "Num$is_between", "func(x:Num,low:Num,high:Num -> Bool)"},
+ {"isinf", "Num$isinf", "func(n:Num -> Bool)"}, {"isfinite", "Num$isfinite", "func(n:Num -> Bool)"},
+ {"modulo", "Num$mod", "func(x,y:Num -> Num)"}, {"modulo1", "Num$mod1", "func(x,y:Num -> Num)"},
+ C(2_SQRTPI), C(E), C(PI_2), C(2_PI), C(1_PI), C(LN10), C(LN2), C(LOG2E), C(PI), C(PI_4), C(SQRT2),
+ C(SQRT1_2), {"INF", "(Num_t)(INFINITY)", "Num"}, {"TAU", "(Num_t)(2.*M_PI)", "Num"},
+ {"mix", "Num$mix", "func(amount,x,y:Num -> Num)"},
+ {"parse", "Num$parse", "func(text:Text, remainder:&Text? = none -> Num?)"},
+ {"abs", "fabs", "func(n:Num -> Num)"}, F_opt(acos), F_opt(acosh), F_opt(asin), F(asinh), F(atan),
+ F_opt(atanh), F(cbrt), F(ceil), F_opt(cos), F(cosh), F(erf), F(erfc), F(exp), F(exp2), F(expm1),
+ F(floor), F(j0), F(j1), F_opt(log), F_opt(log10), F_opt(log1p), F_opt(log2), F(logb), F(rint),
+ F(round), F(significand), F_opt(sin), F(sinh), F_opt(sqrt), F_opt(tan), F(tanh), F_opt(tgamma),
+ F(trunc), F_opt(y0), F_opt(y1), F2(atan2), F2(copysign), F2(fdim), F2(hypot), F2(nextafter), )},
#undef F2
#undef F_opt
#undef F
#undef C
-#define C(name) {#name, "(Num32_t)(M_"#name")", "Num32"}
-#define F(name) {#name, #name"f", "func(n:Num32 -> Num32)"}
-#define F_opt(name) {#name, #name"f", "func(n:Num32 -> Num32?)"}
-#define F2(name) {#name, #name"f", "func(x,y:Num32 -> Num32)"}
- {"Num32", Type(NumType, .bits=TYPE_NBITS32), Text("Num32_t"), Text("Num32$info"), TypedList(ns_entry_t,
- {"near", "Num32$near", "func(x,y:Num32, ratio=Num32(1e-9), min_epsilon=Num32(1e-9) -> Bool)"},
- {"clamped", "Num32$clamped", "func(x,low,high:Num32 -> Num32)"},
- {"percent", "Num32$percent", "func(n:Num32,precision=Num32(.01) -> Text)"},
- {"with_precision", "Num32$with_precision", "func(n:Num32,precision:Num32 -> Num32)"},
- {"is_between", "Num32$is_between", "func(x:Num32,low:Num32,high:Num32 -> Bool)"},
- {"isinf", "Num32$isinf", "func(n:Num32 -> Bool)"},
- {"isfinite", "Num32$isfinite", "func(n:Num32 -> Bool)"},
- C(2_SQRTPI), C(E), C(PI_2), C(2_PI), C(1_PI), C(LN10), C(LN2), C(LOG2E),
- C(PI), C(PI_4), C(SQRT2), C(SQRT1_2),
- {"INF", "(Num32_t)(INFINITY)", "Num32"},
- {"TAU", "(Num32_t)(2.f*M_PI)", "Num32"},
- {"mix", "Num32$mix", "func(amount,x,y:Num32 -> Num32)"},
- {"parse", "Num32$parse", "func(text:Text, remainder:&Text? = none -> Num32?)"},
- {"abs", "fabsf", "func(n:Num32 -> Num32)"},
- {"modulo", "Num32$mod", "func(x,y:Num32 -> Num32)"},
- {"modulo1", "Num32$mod1", "func(x,y:Num32 -> Num32)"},
- F_opt(acos), F_opt(acosh), F_opt(asin), F(asinh), F(atan), F_opt(atanh),
- F(cbrt), F(ceil), F_opt(cos), F(cosh), F(erf), F(erfc),
- F(exp), F(exp2), F(expm1), F(floor), F(j0), F(j1), F_opt(log), F_opt(log10), F_opt(log1p),
- F_opt(log2), F(logb), F(rint), F(round), F(significand), F_opt(sin), F(sinh), F_opt(sqrt),
- F_opt(tan), F(tanh), F_opt(tgamma), F(trunc), F_opt(y0), F_opt(y1),
- F2(atan2), F2(copysign), F2(fdim), F2(hypot), F2(nextafter),
- )},
- {"CString", Type(CStringType), Text("char*"), Text("CString$info"), TypedList(ns_entry_t,
- {"as_text", "Text$from_str", "func(str:CString -> Text)"},
- )},
+#define C(name) {#name, "(Num32_t)(M_" #name ")", "Num32"}
+#define F(name) {#name, #name "f", "func(n:Num32 -> Num32)"}
+#define F_opt(name) {#name, #name "f", "func(n:Num32 -> Num32?)"}
+#define F2(name) {#name, #name "f", "func(x,y:Num32 -> Num32)"}
+ {"Num32", Type(NumType, .bits = TYPE_NBITS32), Text("Num32_t"), Text("Num32$info"),
+ TypedList(
+ ns_entry_t, {"near", "Num32$near", "func(x,y:Num32, ratio=Num32(1e-9), min_epsilon=Num32(1e-9) -> Bool)"},
+ {"clamped", "Num32$clamped", "func(x,low,high:Num32 -> Num32)"},
+ {"percent", "Num32$percent", "func(n:Num32,precision=Num32(.01) -> Text)"},
+ {"with_precision", "Num32$with_precision", "func(n:Num32,precision:Num32 -> Num32)"},
+ {"is_between", "Num32$is_between", "func(x:Num32,low:Num32,high:Num32 -> Bool)"},
+ {"isinf", "Num32$isinf", "func(n:Num32 -> Bool)"}, {"isfinite", "Num32$isfinite", "func(n:Num32 -> Bool)"},
+ C(2_SQRTPI), C(E), C(PI_2), C(2_PI), C(1_PI), C(LN10), C(LN2), C(LOG2E), C(PI), C(PI_4), C(SQRT2),
+ C(SQRT1_2), {"INF", "(Num32_t)(INFINITY)", "Num32"}, {"TAU", "(Num32_t)(2.f*M_PI)", "Num32"},
+ {"mix", "Num32$mix", "func(amount,x,y:Num32 -> Num32)"},
+ {"parse", "Num32$parse", "func(text:Text, remainder:&Text? = none -> Num32?)"},
+ {"abs", "fabsf", "func(n:Num32 -> Num32)"}, {"modulo", "Num32$mod", "func(x,y:Num32 -> Num32)"},
+ {"modulo1", "Num32$mod1", "func(x,y:Num32 -> Num32)"}, F_opt(acos), F_opt(acosh), F_opt(asin), F(asinh),
+ F(atan), F_opt(atanh), F(cbrt), F(ceil), F_opt(cos), F(cosh), F(erf), F(erfc), F(exp), F(exp2), F(expm1),
+ F(floor), F(j0), F(j1), F_opt(log), F_opt(log10), F_opt(log1p), F_opt(log2), F(logb), F(rint), F(round),
+ F(significand), F_opt(sin), F(sinh), F_opt(sqrt), F_opt(tan), F(tanh), F_opt(tgamma), F(trunc), F_opt(y0),
+ F_opt(y1), F2(atan2), F2(copysign), F2(fdim), F2(hypot), F2(nextafter), )},
+ {"CString", Type(CStringType), Text("char*"), Text("CString$info"),
+ TypedList(ns_entry_t, {"as_text", "Text$from_str", "func(str:CString -> Text)"}, )},
#undef F2
#undef F_opt
#undef F
#undef C
- {"PathType", PATH_TYPE_TYPE, Text("PathType_t"), Text("PathType$info"), TypedList(ns_entry_t,
- {"Relative", "((PathType_t){.$tag=PATH_RELATIVE})", "PathType"},
- {"Absolute", "((PathType_t){.$tag=PATH_ABSOLUTE})", "PathType"},
- {"Home", "((PathType_t){.$tag=PATH_HOME})", "PathType"},
- )},
- {"Path", PATH_TYPE, Text("Path_t"), Text("Path$info"), TypedList(ns_entry_t,
- {"accessed", "Path$accessed", "func(path:Path, follow_symlinks=yes -> Int64?)"},
- {"append", "Path$append", "func(path:Path, text:Text, permissions=Int32(0o644))"},
- {"append_bytes", "Path$append_bytes", "func(path:Path, bytes:[Byte], permissions=Int32(0o644))"},
- {"base_name", "Path$base_name", "func(path:Path -> Text)"},
- {"by_line", "Path$by_line", "func(path:Path -> func(->Text?)?)"},
- {"can_execute", "Path$can_execute", "func(path:Path -> Bool)"},
- {"can_read", "Path$can_read", "func(path:Path -> Bool)"},
- {"can_write", "Path$can_write", "func(path:Path -> Bool)"},
- {"changed", "Path$changed", "func(path:Path, follow_symlinks=yes -> Int64?)"},
- {"child", "Path$child", "func(path:Path, child:Text -> Path)"},
- {"children", "Path$children", "func(path:Path, include_hidden=no -> [Path])"},
- {"concatenated_with", "Path$concat", "func(a,b:Path -> Path)"},
- {"create_directory", "Path$create_directory", "func(path:Path, permissions=Int32(0o755))"},
- {"current_dir", "Path$current_dir", "func(->Path)"},
- {"exists", "Path$exists", "func(path:Path -> Bool)"},
- {"expand_home", "Path$expand_home", "func(path:Path -> Path)"},
- {"extension", "Path$extension", "func(path:Path, full=yes -> Text)"},
- {"files", "Path$children", "func(path:Path, include_hidden=no -> [Path])"},
- {"from_components", "Path$from_components", "func(components:[Text] -> Path)"},
- {"glob", "Path$glob", "func(path:Path -> [Path])"},
- {"group", "Path$group", "func(path:Path, follow_symlinks=yes -> Text?)"},
- {"has_extension", "Path$has_extension", "func(path:Path, extension:Text -> Bool)"},
- {"is_directory", "Path$is_directory", "func(path:Path, follow_symlinks=yes -> Bool)"},
- {"is_file", "Path$is_file", "func(path:Path, follow_symlinks=yes -> Bool)"},
- {"is_pipe", "Path$is_pipe", "func(path:Path, follow_symlinks=yes -> Bool)"},
- {"is_socket", "Path$is_socket", "func(path:Path, follow_symlinks=yes -> Bool)"},
- {"is_symlink", "Path$is_symlink", "func(path:Path -> Bool)"},
- {"modified", "Path$modified", "func(path:Path, follow_symlinks=yes -> Int64?)"},
- {"owner", "Path$owner", "func(path:Path, follow_symlinks=yes -> Text?)"},
- {"parent", "Path$parent", "func(path:Path -> Path)"},
- {"read", "Path$read", "func(path:Path -> Text?)"},
- {"read_bytes", "Path$read_bytes", "func(path:Path, limit:Int?=none -> [Byte]?)"},
- {"relative_to", "Path$relative_to", "func(path:Path, relative_to:Path -> Path)"},
- {"remove", "Path$remove", "func(path:Path, ignore_missing=no)"},
- {"resolved", "Path$resolved", "func(path:Path, relative_to=(./) -> Path)"},
- {"set_owner", "Path$set_owner", "func(path:Path, owner:Text?=none, group:Text?=none, follow_symlinks=yes)"},
- {"sibling", "Path$sibling", "func(path:Path, name:Text -> Path)"},
- {"subdirectories", "Path$children", "func(path:Path, include_hidden=no -> [Path])"},
- {"unique_directory", "Path$unique_directory", "func(path:Path -> Path)"},
- {"write", "Path$write", "func(path:Path, text:Text, permissions=Int32(0o644))"},
- {"write_bytes", "Path$write_bytes", "func(path:Path, bytes:[Byte], permissions=Int32(0o644))"},
- {"write_unique", "Path$write_unique", "func(path:Path, text:Text -> Path)"},
- {"write_unique_bytes", "Path$write_unique_bytes", "func(path:Path, bytes:[Byte] -> Path)"},
- )},
- {"Text", TEXT_TYPE, Text("Text_t"), Text("Text$info"), TypedList(ns_entry_t,
- {"as_c_string", "Text$as_c_string", "func(text:Text -> CString)"},
- {"at", "Text$cluster", "func(text:Text, index:Int -> Text)"},
- {"by_line", "Text$by_line", "func(text:Text -> func(->Text?))"},
- {"by_split", "Text$by_split", "func(text:Text, delimiter='' -> func(->Text?))"},
- {"by_split_any", "Text$by_split_any", "func(text:Text, delimiters=' \\t\\r\\n' -> func(->Text?))"},
- {"bytes", "Text$utf8_bytes", "func(text:Text -> [Byte])"},
- {"caseless_equals", "Text$equal_ignoring_case", "func(a,b:Text, language='C' -> Bool)"},
- {"codepoint_names", "Text$codepoint_names", "func(text:Text -> [Text])"},
- {"ends_with", "Text$ends_with", "func(text,suffix:Text, remainder:&Text? = none -> Bool)"},
- {"from", "Text$from", "func(text:Text, first:Int -> Text)"},
- {"from_bytes", "Text$from_bytes", "func(bytes:[Byte] -> Text?)"},
- {"from_c_string", "Text$from_str", "func(str:CString -> Text?)"},
- {"from_codepoint_names", "Text$from_codepoint_names", "func(codepoint_names:[Text] -> Text?)"},
- {"from_codepoints", "Text$from_codepoints", "func(codepoints:[Int32] -> Text)"},
- {"from_text", "Path$from_text", "func(text:Text -> Path)"},
- {"has", "Text$has", "func(text:Text, target:Text -> Bool)"},
- {"join", "Text$join", "func(glue:Text, pieces:[Text] -> Text)"},
- {"layout", "Text$layout", "func(text:Text -> Text)"},
- {"left_pad", "Text$left_pad", "func(text:Text, count:Int, pad=' ', language='C' -> Text)"},
- {"lines", "Text$lines", "func(text:Text -> [Text])"},
- {"lower", "Text$lower", "func(text:Text, language='C' -> Text)"},
- {"memory_size", "Text$memory_size", "func(text:Text -> Int)"},
- {"middle_pad", "Text$middle_pad", "func(text:Text, count:Int, pad=' ', language='C' -> Text)"},
- {"quoted", "Text$quoted", "func(text:Text, color=no, quotation_mark='\"' -> Text)"},
- {"repeat", "Text$repeat", "func(text:Text, count:Int -> Text)"},
- {"replace", "Text$replace", "func(text:Text, target:Text, replacement:Text -> Text)"},
- {"reversed", "Text$reversed", "func(text:Text -> Text)"},
- {"right_pad", "Text$right_pad", "func(text:Text, count:Int, pad=' ', language='C' -> Text)"},
- {"slice", "Text$slice", "func(text:Text, from=1, to=-1 -> Text)"},
- {"split", "Text$split", "func(text:Text, delimiter='' -> [Text])"},
- {"split_any", "Text$split_any", "func(text:Text, delimiters=' \\t\\r\\n' -> [Text])"},
- {"starts_with", "Text$starts_with", "func(text,prefix:Text, remainder:&Text? = none -> Bool)"},
- {"title", "Text$title", "func(text:Text, language='C' -> Text)"},
- {"to", "Text$to", "func(text:Text, last:Int -> Text)"},
- {"translate", "Text$translate", "func(text:Text, translations:{Text=Text} -> Text)"},
- {"trim", "Text$trim", "func(text:Text, to_trim=\" \t\r\n\", left=yes, right=yes -> Text)"},
- {"upper", "Text$upper", "func(text:Text, language='C' -> Text)"},
- {"utf32_codepoints", "Text$utf32_codepoints", "func(text:Text -> [Int32])"},
- {"width", "Text$width", "func(text:Text, language='C' -> Int)"},
- {"without_prefix", "Text$without_prefix", "func(text,prefix:Text -> Text)"},
- {"without_suffix", "Text$without_suffix", "func(text,suffix:Text -> Text)"},
- )},
+ {"PathType", PATH_TYPE_TYPE, Text("PathType_t"), Text("PathType$info"),
+ TypedList(ns_entry_t, {"Relative", "((PathType_t){.$tag=PATH_RELATIVE})", "PathType"},
+ {"Absolute", "((PathType_t){.$tag=PATH_ABSOLUTE})", "PathType"},
+ {"Home", "((PathType_t){.$tag=PATH_HOME})", "PathType"}, )},
+ {"Path", PATH_TYPE, Text("Path_t"), Text("Path$info"),
+ TypedList(
+ ns_entry_t, {"accessed", "Path$accessed", "func(path:Path, follow_symlinks=yes -> Int64?)"},
+ {"append", "Path$append", "func(path:Path, text:Text, permissions=Int32(0o644))"},
+ {"append_bytes", "Path$append_bytes", "func(path:Path, bytes:[Byte], permissions=Int32(0o644))"},
+ {"base_name", "Path$base_name", "func(path:Path -> Text)"},
+ {"by_line", "Path$by_line", "func(path:Path -> func(->Text?)?)"},
+ {"can_execute", "Path$can_execute", "func(path:Path -> Bool)"},
+ {"can_read", "Path$can_read", "func(path:Path -> Bool)"},
+ {"can_write", "Path$can_write", "func(path:Path -> Bool)"},
+ {"changed", "Path$changed", "func(path:Path, follow_symlinks=yes -> Int64?)"},
+ {"child", "Path$child", "func(path:Path, child:Text -> Path)"},
+ {"children", "Path$children", "func(path:Path, include_hidden=no -> [Path])"},
+ {"concatenated_with", "Path$concat", "func(a,b:Path -> Path)"},
+ {"create_directory", "Path$create_directory", "func(path:Path, permissions=Int32(0o755))"},
+ {"current_dir", "Path$current_dir", "func(->Path)"}, {"exists", "Path$exists", "func(path:Path -> Bool)"},
+ {"expand_home", "Path$expand_home", "func(path:Path -> Path)"},
+ {"extension", "Path$extension", "func(path:Path, full=yes -> Text)"},
+ {"files", "Path$children", "func(path:Path, include_hidden=no -> [Path])"},
+ {"from_components", "Path$from_components", "func(components:[Text] -> Path)"},
+ {"glob", "Path$glob", "func(path:Path -> [Path])"},
+ {"group", "Path$group", "func(path:Path, follow_symlinks=yes -> Text?)"},
+ {"has_extension", "Path$has_extension", "func(path:Path, extension:Text -> Bool)"},
+ {"is_directory", "Path$is_directory", "func(path:Path, follow_symlinks=yes -> Bool)"},
+ {"is_file", "Path$is_file", "func(path:Path, follow_symlinks=yes -> Bool)"},
+ {"is_pipe", "Path$is_pipe", "func(path:Path, follow_symlinks=yes -> Bool)"},
+ {"is_socket", "Path$is_socket", "func(path:Path, follow_symlinks=yes -> Bool)"},
+ {"is_symlink", "Path$is_symlink", "func(path:Path -> Bool)"},
+ {"modified", "Path$modified", "func(path:Path, follow_symlinks=yes -> Int64?)"},
+ {"owner", "Path$owner", "func(path:Path, follow_symlinks=yes -> Text?)"},
+ {"parent", "Path$parent", "func(path:Path -> Path)"}, {"read", "Path$read", "func(path:Path -> Text?)"},
+ {"read_bytes", "Path$read_bytes", "func(path:Path, limit:Int?=none -> [Byte]?)"},
+ {"relative_to", "Path$relative_to", "func(path:Path, relative_to:Path -> Path)"},
+ {"remove", "Path$remove", "func(path:Path, ignore_missing=no)"},
+ {"resolved", "Path$resolved", "func(path:Path, relative_to=(./) -> Path)"},
+ {"set_owner", "Path$set_owner",
+ "func(path:Path, owner:Text?=none, group:Text?=none, follow_symlinks=yes)"},
+ {"sibling", "Path$sibling", "func(path:Path, name:Text -> Path)"},
+ {"subdirectories", "Path$children", "func(path:Path, include_hidden=no -> [Path])"},
+ {"unique_directory", "Path$unique_directory", "func(path:Path -> Path)"},
+ {"write", "Path$write", "func(path:Path, text:Text, permissions=Int32(0o644))"},
+ {"write_bytes", "Path$write_bytes", "func(path:Path, bytes:[Byte], permissions=Int32(0o644))"},
+ {"write_unique", "Path$write_unique", "func(path:Path, text:Text -> Path)"},
+ {"write_unique_bytes", "Path$write_unique_bytes", "func(path:Path, bytes:[Byte] -> Path)"}, )},
+ {"Text", TEXT_TYPE, Text("Text_t"), Text("Text$info"),
+ TypedList(ns_entry_t, {"as_c_string", "Text$as_c_string", "func(text:Text -> CString)"},
+ {"at", "Text$cluster", "func(text:Text, index:Int -> Text)"},
+ {"by_line", "Text$by_line", "func(text:Text -> func(->Text?))"},
+ {"by_split", "Text$by_split", "func(text:Text, delimiter='' -> func(->Text?))"},
+ {"by_split_any", "Text$by_split_any", "func(text:Text, delimiters=' \\t\\r\\n' -> func(->Text?))"},
+ {"bytes", "Text$utf8_bytes", "func(text:Text -> [Byte])"},
+ {"caseless_equals", "Text$equal_ignoring_case", "func(a,b:Text, language='C' -> Bool)"},
+ {"codepoint_names", "Text$codepoint_names", "func(text:Text -> [Text])"},
+ {"ends_with", "Text$ends_with", "func(text,suffix:Text, remainder:&Text? = none -> Bool)"},
+ {"from", "Text$from", "func(text:Text, first:Int -> Text)"},
+ {"from_bytes", "Text$from_bytes", "func(bytes:[Byte] -> Text?)"},
+ {"from_c_string", "Text$from_str", "func(str:CString -> Text?)"},
+ {"from_codepoint_names", "Text$from_codepoint_names", "func(codepoint_names:[Text] -> Text?)"},
+ {"from_codepoints", "Text$from_codepoints", "func(codepoints:[Int32] -> Text)"},
+ {"from_text", "Path$from_text", "func(text:Text -> Path)"},
+ {"has", "Text$has", "func(text:Text, target:Text -> Bool)"},
+ {"join", "Text$join", "func(glue:Text, pieces:[Text] -> Text)"},
+ {"layout", "Text$layout", "func(text:Text -> Text)"},
+ {"left_pad", "Text$left_pad", "func(text:Text, count:Int, pad=' ', language='C' -> Text)"},
+ {"lines", "Text$lines", "func(text:Text -> [Text])"},
+ {"lower", "Text$lower", "func(text:Text, language='C' -> Text)"},
+ {"memory_size", "Text$memory_size", "func(text:Text -> Int)"},
+ {"middle_pad", "Text$middle_pad", "func(text:Text, count:Int, pad=' ', language='C' -> Text)"},
+ {"quoted", "Text$quoted", "func(text:Text, color=no, quotation_mark='\"' -> Text)"},
+ {"repeat", "Text$repeat", "func(text:Text, count:Int -> Text)"},
+ {"replace", "Text$replace", "func(text:Text, target:Text, replacement:Text -> Text)"},
+ {"reversed", "Text$reversed", "func(text:Text -> Text)"},
+ {"right_pad", "Text$right_pad", "func(text:Text, count:Int, pad=' ', language='C' -> Text)"},
+ {"slice", "Text$slice", "func(text:Text, from=1, to=-1 -> Text)"},
+ {"split", "Text$split", "func(text:Text, delimiter='' -> [Text])"},
+ {"split_any", "Text$split_any", "func(text:Text, delimiters=' \\t\\r\\n' -> [Text])"},
+ {"starts_with", "Text$starts_with", "func(text,prefix:Text, remainder:&Text? = none -> Bool)"},
+ {"title", "Text$title", "func(text:Text, language='C' -> Text)"},
+ {"to", "Text$to", "func(text:Text, last:Int -> Text)"},
+ {"translate", "Text$translate", "func(text:Text, translations:{Text=Text} -> Text)"},
+ {"trim", "Text$trim", "func(text:Text, to_trim=\" \t\r\n\", left=yes, right=yes -> Text)"},
+ {"upper", "Text$upper", "func(text:Text, language='C' -> Text)"},
+ {"utf32_codepoints", "Text$utf32_codepoints", "func(text:Text -> [Int32])"},
+ {"width", "Text$width", "func(text:Text, language='C' -> Int)"},
+ {"without_prefix", "Text$without_prefix", "func(text,prefix:Text -> Text)"},
+ {"without_suffix", "Text$without_suffix", "func(text,suffix:Text -> Text)"}, )},
};
- for (size_t i = 0; i < sizeof(global_types)/sizeof(global_types[0]); i++) {
+ for (size_t i = 0; i < sizeof(global_types) / sizeof(global_types[0]); i++) {
env_t *ns_env = NULL;
switch (global_types[i].type->tag) {
- case TextType:
- ns_env = Match(global_types[i].type, TextType)->env;
- break;
- case StructType:
- ns_env = Match(global_types[i].type, StructType)->env;
- break;
- case EnumType:
- ns_env = Match(global_types[i].type, EnumType)->env;
- break;
+ case TextType: ns_env = Match(global_types[i].type, TextType)->env; break;
+ case StructType: ns_env = Match(global_types[i].type, StructType)->env; break;
+ case EnumType: ns_env = Match(global_types[i].type, EnumType)->env; break;
default: break;
}
if (ns_env == NULL) ns_env = namespace_env(env, global_types[i].name);
- binding_t *binding = new(binding_t, .type=Type(TypeInfoType, .name=global_types[i].name, .type=global_types[i].type, .env=ns_env),
- .code=global_types[i].typeinfo);
+ binding_t *binding =
+ new (binding_t,
+ .type = Type(TypeInfoType, .name = global_types[i].name, .type = global_types[i].type, .env = ns_env),
+ .code = global_types[i].typeinfo);
Table$str_set(env->globals, global_types[i].name, binding);
Table$str_set(env->types, global_types[i].name, global_types[i].type);
}
- for (size_t i = 0; i < sizeof(global_types)/sizeof(global_types[0]); i++) {
+ for (size_t i = 0; i < sizeof(global_types) / sizeof(global_types[0]); i++) {
binding_t *type_binding = Table$str_get(*env->globals, global_types[i].name);
assert(type_binding);
env_t *ns_env = Match(type_binding->type, TypeInfoType)->env;
for (int64_t j = 0; j < global_types[i].namespace.length; j++) {
- ns_entry_t *entry = global_types[i].namespace.data + j*global_types[i].namespace.stride;
+ ns_entry_t *entry = global_types[i].namespace.data + j * global_types[i].namespace.stride;
type_t *type = parse_type_string(ns_env, entry->type_str);
if (!type) compiler_err(NULL, NULL, NULL, "Couldn't parse type string: ", entry->type_str);
if (type->tag == ClosureType) type = Match(type, ClosureType)->fn;
@@ -415,106 +371,80 @@ env_t *global_env(bool source_mapping)
}
}
-
// Conversion constructors:
-#define ADD_CONSTRUCTORS(type_name, ...) do {\
- env_t *ns_env = namespace_env(env, type_name); \
- struct { const char *c_name, *type_str; } constructor_infos[] = {__VA_ARGS__}; \
- for (size_t i = 0; i < sizeof(constructor_infos)/sizeof(constructor_infos[0]); i++) { \
- type_t *t = parse_type_string(ns_env, constructor_infos[i].type_str); \
- List$insert(&ns_env->namespace->constructors, \
- ((binding_t[1]){{.code=Text$from_str(constructor_infos[i].c_name), \
- .type=Match(t, ClosureType)->fn}}), I(0), sizeof(binding_t)); \
- } \
-} while (0)
-
- ADD_CONSTRUCTORS("Bool",
- {"Bool$from_byte", "func(b:Byte -> Bool)"},
- {"Bool$from_int8", "func(i:Int8 -> Bool)"},
- {"Bool$from_int16", "func(i:Int16 -> Bool)"},
- {"Bool$from_int32", "func(i:Int32 -> Bool)"},
- {"Bool$from_int64", "func(i:Int64 -> Bool)"},
- {"Bool$from_int", "func(i:Int -> Bool)"});
- ADD_CONSTRUCTORS("Byte",
- {"Byte$from_bool", "func(b:Bool -> Byte)"},
- {"Byte$from_int8", "func(i:Int8 -> Byte)"},
+#define ADD_CONSTRUCTORS(type_name, ...) \
+ do { \
+ env_t *ns_env = namespace_env(env, type_name); \
+ struct { \
+ const char *c_name, *type_str; \
+ } constructor_infos[] = {__VA_ARGS__}; \
+ for (size_t i = 0; i < sizeof(constructor_infos) / sizeof(constructor_infos[0]); i++) { \
+ type_t *t = parse_type_string(ns_env, constructor_infos[i].type_str); \
+ List$insert(&ns_env->namespace->constructors, \
+ ((binding_t[1]){ \
+ {.code = Text$from_str(constructor_infos[i].c_name), .type = Match(t, ClosureType)->fn}}), \
+ I(0), sizeof(binding_t)); \
+ } \
+ } while (0)
+
+ ADD_CONSTRUCTORS("Bool", {"Bool$from_byte", "func(b:Byte -> Bool)"}, {"Bool$from_int8", "func(i:Int8 -> Bool)"},
+ {"Bool$from_int16", "func(i:Int16 -> Bool)"}, {"Bool$from_int32", "func(i:Int32 -> Bool)"},
+ {"Bool$from_int64", "func(i:Int64 -> Bool)"}, {"Bool$from_int", "func(i:Int -> Bool)"});
+ ADD_CONSTRUCTORS("Byte", {"Byte$from_bool", "func(b:Bool -> Byte)"}, {"Byte$from_int8", "func(i:Int8 -> Byte)"},
{"Byte$from_int16", "func(i:Int16, truncate=no -> Byte)"},
{"Byte$from_int32", "func(i:Int32, truncate=no -> Byte)"},
{"Byte$from_int64", "func(i:Int64, truncate=no -> Byte)"},
{"Byte$from_int", "func(i:Int, truncate=no -> Byte)"});
- ADD_CONSTRUCTORS("Int",
- {"Int$from_bool", "func(b:Bool -> Int)"},
- {"Int$from_byte", "func(b:Byte -> Int)"},
- {"Int$from_int8", "func(i:Int8 -> Int)"},
- {"Int$from_int16", "func(i:Int16 -> Int)"},
- {"Int$from_int32", "func(i:Int32 -> Int)"},
- {"Int$from_int64", "func(i:Int64 -> Int)"},
+ ADD_CONSTRUCTORS("Int", {"Int$from_bool", "func(b:Bool -> Int)"}, {"Int$from_byte", "func(b:Byte -> Int)"},
+ {"Int$from_int8", "func(i:Int8 -> Int)"}, {"Int$from_int16", "func(i:Int16 -> Int)"},
+ {"Int$from_int32", "func(i:Int32 -> Int)"}, {"Int$from_int64", "func(i:Int64 -> Int)"},
{"Int$from_num", "func(n:Num, truncate=no -> Int)"},
{"Int$from_num32", "func(n:Num32, truncate=no -> Int)"});
- ADD_CONSTRUCTORS("Int64",
- {"Int64$from_bool", "func(b:Bool -> Int64)"},
- {"Int64$from_byte", "func(b:Byte -> Int64)"},
- {"Int64$from_int8", "func(i:Int8 -> Int64)"},
- {"Int64$from_int16", "func(i:Int16 -> Int64)"},
- {"Int64$from_int32", "func(i:Int32 -> Int64)"},
+ ADD_CONSTRUCTORS("Int64", {"Int64$from_bool", "func(b:Bool -> Int64)"},
+ {"Int64$from_byte", "func(b:Byte -> Int64)"}, {"Int64$from_int8", "func(i:Int8 -> Int64)"},
+ {"Int64$from_int16", "func(i:Int16 -> Int64)"}, {"Int64$from_int32", "func(i:Int32 -> Int64)"},
{"Int64$from_int", "func(i:Int, truncate=no -> Int64)"},
{"Int64$from_num", "func(n:Num, truncate=no -> Int64)"},
{"Int64$from_num32", "func(n:Num32, truncate=no -> Int64)"});
- ADD_CONSTRUCTORS("Int32",
- {"Int32$from_bool", "func(b:Bool -> Int32)"},
- {"Int32$from_byte", "func(b:Byte -> Int32)"},
- {"Int32$from_int8", "func(i:Int8 -> Int32)"},
+ ADD_CONSTRUCTORS("Int32", {"Int32$from_bool", "func(b:Bool -> Int32)"},
+ {"Int32$from_byte", "func(b:Byte -> Int32)"}, {"Int32$from_int8", "func(i:Int8 -> Int32)"},
{"Int32$from_int16", "func(i:Int16 -> Int32)"},
{"Int32$from_int64", "func(i:Int64, truncate=no -> Int32)"},
{"Int32$from_int", "func(i:Int, truncate=no -> Int32)"},
{"Int32$from_num", "func(n:Num, truncate=no -> Int32)"},
{"Int32$from_num32", "func(n:Num32, truncate=no -> Int32)"});
- ADD_CONSTRUCTORS("Int16",
- {"Int16$from_bool", "func(b:Bool -> Int16)"},
- {"Int16$from_byte", "func(b:Byte -> Int16)"},
- {"Int16$from_int8", "func(i:Int8 -> Int16)"},
+ ADD_CONSTRUCTORS("Int16", {"Int16$from_bool", "func(b:Bool -> Int16)"},
+ {"Int16$from_byte", "func(b:Byte -> Int16)"}, {"Int16$from_int8", "func(i:Int8 -> Int16)"},
{"Int16$from_int32", "func(i:Int32, truncate=no -> Int16)"},
{"Int16$from_int64", "func(i:Int64, truncate=no -> Int16)"},
{"Int16$from_int", "func(i:Int, truncate=no -> Int16)"},
{"Int16$from_num", "func(n:Num, truncate=no -> Int16)"},
{"Int16$from_num32", "func(n:Num32, truncate=no -> Int16)"});
- ADD_CONSTRUCTORS("Int8",
- {"Int8$from_bool", "func(b:Bool -> Int8)"},
- {"Int8$from_byte", "func(b:Byte -> Int8)"},
+ ADD_CONSTRUCTORS("Int8", {"Int8$from_bool", "func(b:Bool -> Int8)"}, {"Int8$from_byte", "func(b:Byte -> Int8)"},
{"Int8$from_int16", "func(i:Int16, truncate=no -> Int8)"},
{"Int8$from_int32", "func(i:Int32, truncate=no -> Int8)"},
{"Int8$from_int64", "func(i:Int64, truncate=no -> Int8)"},
{"Int8$from_int", "func(i:Int, truncate=no -> Int8)"},
{"Int8$from_num", "func(n:Num, truncate=no -> Int8)"},
{"Int8$from_num32", "func(n:Num32, truncate=no -> Int8)"});
- ADD_CONSTRUCTORS("Num",
- {"Num$from_bool", "func(b:Bool -> Num)"},
- {"Num$from_byte", "func(b:Byte -> Num)"},
- {"Num$from_int8", "func(i:Int8 -> Num)"},
- {"Num$from_int16", "func(i:Int16 -> Num)"},
+ ADD_CONSTRUCTORS("Num", {"Num$from_bool", "func(b:Bool -> Num)"}, {"Num$from_byte", "func(b:Byte -> Num)"},
+ {"Num$from_int8", "func(i:Int8 -> Num)"}, {"Num$from_int16", "func(i:Int16 -> Num)"},
{"Num$from_int32", "func(i:Int32 -> Num)"},
{"Num$from_int64", "func(i:Int64, truncate=no -> Num)"},
- {"Num$from_int", "func(i:Int, truncate=no -> Num)"},
- {"Num$from_num32", "func(n:Num32 -> Num)"});
- ADD_CONSTRUCTORS("Num32",
- {"Num32$from_bool", "func(b:Bool -> Num32)"},
- {"Num32$from_byte", "func(b:Byte -> Num32)"},
- {"Num32$from_int8", "func(i:Int8 -> Num32)"},
- {"Num32$from_int16", "func(i:Int16 -> Num32)"},
- {"Num32$from_int32", "func(i:Int32, truncate=no -> Num32)"},
- {"Num32$from_int64", "func(i:Int64, truncate=no -> Num32)"},
- {"Num32$from_int", "func(i:Int, truncate=no -> Num32)"},
- {"Num32$from_num", "func(n:Num -> Num32)"});
- ADD_CONSTRUCTORS("Path",
- {"Path$escape_text", "func(text:Text -> Path)"},
- {"Path$escape_path", "func(path:Path -> Path)"},
- {"Int$value_as_text", "func(i:Int -> Path)"});
+ {"Num$from_int", "func(i:Int, truncate=no -> Num)"}, {"Num$from_num32", "func(n:Num32 -> Num)"});
+ ADD_CONSTRUCTORS(
+ "Num32", {"Num32$from_bool", "func(b:Bool -> Num32)"}, {"Num32$from_byte", "func(b:Byte -> Num32)"},
+ {"Num32$from_int8", "func(i:Int8 -> Num32)"}, {"Num32$from_int16", "func(i:Int16 -> Num32)"},
+ {"Num32$from_int32", "func(i:Int32, truncate=no -> Num32)"},
+ {"Num32$from_int64", "func(i:Int64, truncate=no -> Num32)"},
+ {"Num32$from_int", "func(i:Int, truncate=no -> Num32)"}, {"Num32$from_num", "func(n:Num -> Num32)"});
+ ADD_CONSTRUCTORS("Path", {"Path$escape_text", "func(text:Text -> Path)"},
+ {"Path$escape_path", "func(path:Path -> Path)"}, {"Int$value_as_text", "func(i:Int -> Path)"});
ADD_CONSTRUCTORS("CString", {"Text$as_c_string", "func(text:Text -> CString)"});
#undef ADD_CONSTRUCTORS
set_binding(namespace_env(env, "Path"), "from_text",
- NewFunctionType(PATH_TYPE, {.name="text", .type=TEXT_TYPE}),
- Text("Path$from_text"));
+ NewFunctionType(PATH_TYPE, {.name = "text", .type = TEXT_TYPE}), Text("Path$from_text"));
struct {
const char *name, *code, *type_str;
@@ -531,46 +461,46 @@ env_t *global_env(bool source_mapping)
{"sleep", "sleep_num", "func(seconds:Num)"},
};
- for (size_t i = 0; i < sizeof(global_vars)/sizeof(global_vars[0]); i++) {
+ for (size_t i = 0; i < sizeof(global_vars) / sizeof(global_vars[0]); i++) {
type_t *type = parse_type_string(env, global_vars[i].type_str);
- if (!type) compiler_err(NULL, NULL, NULL, "Couldn't parse type string for ", global_vars[i].name, ": ", global_vars[i].type_str);
+ if (!type)
+ compiler_err(NULL, NULL, NULL, "Couldn't parse type string for ", global_vars[i].name, ": ",
+ global_vars[i].type_str);
if (type->tag == ClosureType) type = Match(type, ClosureType)->fn;
- Table$str_set(env->globals, global_vars[i].name, new(binding_t, .type=type, .code=Text$from_str(global_vars[i].code)));
+ Table$str_set(env->globals, global_vars[i].name,
+ new (binding_t, .type = type, .code = Text$from_str(global_vars[i].code)));
}
_global_env = env;
return env;
}
-env_t *load_module_env(env_t *env, ast_t *ast)
-{
+env_t *load_module_env(env_t *env, ast_t *ast) {
const char *name = ast->file->filename;
env_t *cached = Table$str_get(*env->imports, name);
if (cached) return cached;
env_t *module_env = fresh_scope(env);
- module_env->code = new(compilation_unit_t);
+ module_env->code = new (compilation_unit_t);
module_env->namespace_bindings = module_env->locals;
module_env->id_suffix = get_id_suffix(ast->file->filename);
Table$str_set(module_env->imports, name, module_env);
ast_list_t *statements = Match(ast, Block)->statements;
- visit_topologically(statements, (Closure_t){.fn=(void*)prebind_statement, .userdata=module_env});
- visit_topologically(statements, (Closure_t){.fn=(void*)bind_statement, .userdata=module_env});
+ visit_topologically(statements, (Closure_t){.fn = (void *)prebind_statement, .userdata = module_env});
+ visit_topologically(statements, (Closure_t){.fn = (void *)bind_statement, .userdata = module_env});
return module_env;
}
-env_t *fresh_scope(env_t *env)
-{
- env_t *scope = new(env_t);
+env_t *fresh_scope(env_t *env) {
+ env_t *scope = new (env_t);
*scope = *env;
- scope->locals = new(Table_t, .fallback=env->locals);
+ scope->locals = new (Table_t, .fallback = env->locals);
return scope;
}
-env_t *with_enum_scope(env_t *env, type_t *t)
-{
+env_t *with_enum_scope(env_t *env, type_t *t) {
while (t->tag == OptionalType)
t = Match(t, OptionalType)->type;
@@ -578,8 +508,7 @@ env_t *with_enum_scope(env_t *env, type_t *t)
env = fresh_scope(env);
env_t *ns_env = Match(t, EnumType)->env;
for (tag_t *tag = Match(t, EnumType)->tags; tag; tag = tag->next) {
- if (get_binding(env, tag->name))
- continue;
+ if (get_binding(env, tag->name)) continue;
binding_t *b = get_binding(ns_env, tag->name);
assert(b);
Table$str_set(env->locals, tag->name, b);
@@ -587,9 +516,7 @@ env_t *with_enum_scope(env_t *env, type_t *t)
return env;
}
-
-env_t *for_scope(env_t *env, ast_t *ast)
-{
+env_t *for_scope(env_t *env, ast_t *ast) {
DeclareMatch(for_, ast, For);
type_t *iter_t = value_type(get_type(env, for_->iter));
env_t *scope = fresh_scope(env);
@@ -600,8 +527,7 @@ env_t *for_scope(env_t *env, ast_t *ast)
const char *vars[2] = {};
int64_t num_vars = 0;
for (ast_list_t *var = for_->vars; var; var = var->next) {
- if (num_vars >= 2)
- code_err(var->ast, "This is too many variables for this loop");
+ if (num_vars >= 2) code_err(var->ast, "This is too many variables for this loop");
vars[num_vars++] = Match(var->ast, Var)->name;
}
if (num_vars == 1) {
@@ -614,8 +540,7 @@ env_t *for_scope(env_t *env, ast_t *ast)
}
case SetType: {
if (for_->vars) {
- if (for_->vars->next)
- code_err(for_->vars->next->ast, "This is too many variables for this loop");
+ if (for_->vars->next) code_err(for_->vars->next->ast, "This is too many variables for this loop");
type_t *item_type = Match(iter_t, SetType)->item_type;
const char *name = Match(for_->vars->ast, Var)->name;
set_binding(scope, name, item_type, Texts("_$", name));
@@ -626,8 +551,7 @@ env_t *for_scope(env_t *env, ast_t *ast)
const char *vars[2] = {};
int64_t num_vars = 0;
for (ast_list_t *var = for_->vars; var; var = var->next) {
- if (num_vars >= 2)
- code_err(var->ast, "This is too many variables for this loop");
+ if (num_vars >= 2) code_err(var->ast, "This is too many variables for this loop");
vars[num_vars++] = Match(var->ast, Var)->name;
}
@@ -643,19 +567,20 @@ env_t *for_scope(env_t *env, ast_t *ast)
}
case BigIntType: {
if (for_->vars) {
- if (for_->vars->next)
- code_err(for_->vars->next->ast, "This is too many variables for this loop");
+ if (for_->vars->next) code_err(for_->vars->next->ast, "This is too many variables for this loop");
const char *var = Match(for_->vars->ast, Var)->name;
set_binding(scope, var, INT_TYPE, Texts("_$", var));
}
return scope;
}
- case FunctionType: case ClosureType: {
- __typeof(iter_t->__data.FunctionType) *fn = iter_t->tag == ClosureType ? Match(Match(iter_t, ClosureType)->fn, FunctionType) : Match(iter_t, FunctionType);
+ case FunctionType:
+ case ClosureType: {
+ __typeof(iter_t->__data.FunctionType) *fn = iter_t->tag == ClosureType
+ ? Match(Match(iter_t, ClosureType)->fn, FunctionType)
+ : Match(iter_t, FunctionType);
if (for_->vars) {
- if (for_->vars->next)
- code_err(for_->vars->next->ast, "This is too many variables for this loop");
+ if (for_->vars->next) code_err(for_->vars->next->ast, "This is too many variables for this loop");
const char *var = Match(for_->vars->ast, Var)->name;
type_t *non_opt_type = fn->ret->tag == OptionalType ? Match(fn->ret, OptionalType)->type : fn->ret;
set_binding(scope, var, non_opt_type, Texts("_$", var));
@@ -667,14 +592,17 @@ env_t *for_scope(env_t *env, ast_t *ast)
return NULL;
}
-env_t *get_namespace_by_type(env_t *env, type_t *t)
-{
+env_t *get_namespace_by_type(env_t *env, type_t *t) {
t = value_type(t);
switch (t->tag) {
case ListType: return NULL;
case TableType: return NULL;
case CStringType:
- case BoolType: case IntType: case BigIntType: case NumType: case ByteType: {
+ case BoolType:
+ case IntType:
+ case BigIntType:
+ case NumType:
+ case ByteType: {
binding_t *b = get_binding(env, Text$as_c_string(type_to_text(t)));
assert(b);
return Match(b->type, TypeInfoType)->env;
@@ -697,84 +625,72 @@ env_t *get_namespace_by_type(env_t *env, type_t *t)
return NULL;
}
-env_t *namespace_env(env_t *env, const char *namespace_name)
-{
+env_t *namespace_env(env_t *env, const char *namespace_name) {
binding_t *b = get_binding(env, namespace_name);
- if (b)
- return Match(b->type, TypeInfoType)->env;
+ if (b) return Match(b->type, TypeInfoType)->env;
- env_t *ns_env = new(env_t);
+ env_t *ns_env = new (env_t);
*ns_env = *env;
- ns_env->locals = new(Table_t, .fallback=env->locals);
- ns_env->namespace = new(namespace_t, .name=namespace_name, .parent=env->namespace);
+ ns_env->locals = new (Table_t, .fallback = env->locals);
+ ns_env->namespace = new (namespace_t, .name = namespace_name, .parent = env->namespace);
ns_env->namespace_bindings = ns_env->locals;
return ns_env;
}
-PUREFUNC binding_t *get_binding(env_t *env, const char *name)
-{
- return Table$str_get(*env->locals, name);
-}
+PUREFUNC binding_t *get_binding(env_t *env, const char *name) { return Table$str_get(*env->locals, name); }
-binding_t *get_namespace_binding(env_t *env, ast_t *self, const char *name)
-{
+binding_t *get_namespace_binding(env_t *env, ast_t *self, const char *name) {
type_t *self_type = get_type(env, self);
- if (!self_type)
- code_err(self, "I couldn't get this type");
+ if (!self_type) code_err(self, "I couldn't get this type");
env_t *ns_env = get_namespace_by_type(env, self_type);
return ns_env ? get_binding(ns_env, name) : NULL;
}
-PUREFUNC binding_t *get_constructor(env_t *env, type_t *t, arg_ast_t *args, bool allow_underscores)
-{
+PUREFUNC binding_t *get_constructor(env_t *env, type_t *t, arg_ast_t *args, bool allow_underscores) {
env_t *type_env = get_namespace_by_type(env, t);
if (!type_env) return NULL;
List_t constructors = type_env->namespace->constructors;
// Prioritize exact matches:
- for (int64_t i = constructors.length-1; i >= 0; i--) {
- binding_t *b = constructors.data + i*constructors.stride;
+ for (int64_t i = constructors.length - 1; i >= 0; i--) {
+ binding_t *b = constructors.data + i * constructors.stride;
DeclareMatch(fn, b->type, FunctionType);
if (!allow_underscores) {
for (arg_t *arg = fn->args; arg; arg = arg->next)
- if (arg->name[0] == '_')
- goto next_constructor;
+ if (arg->name[0] == '_') goto next_constructor;
}
- if (type_eq(fn->ret, t) && is_valid_call(env, fn->args, args, false))
- return b;
- next_constructor: continue;
+ if (type_eq(fn->ret, t) && is_valid_call(env, fn->args, args, false)) return b;
+ next_constructor:
+ continue;
}
// Fall back to promotion:
- for (int64_t i = constructors.length-1; i >= 0; i--) {
- binding_t *b = constructors.data + i*constructors.stride;
+ for (int64_t i = constructors.length - 1; i >= 0; i--) {
+ binding_t *b = constructors.data + i * constructors.stride;
DeclareMatch(fn, b->type, FunctionType);
if (!allow_underscores) {
for (arg_t *arg = fn->args; arg; arg = arg->next)
- if (arg->name[0] == '_')
- goto next_constructor2;
+ if (arg->name[0] == '_') goto next_constructor2;
}
- if (type_eq(fn->ret, t) && is_valid_call(env, fn->args, args, true))
- return b;
- next_constructor2: continue;
+ if (type_eq(fn->ret, t) && is_valid_call(env, fn->args, args, true)) return b;
+ next_constructor2:
+ continue;
}
return NULL;
}
-PUREFUNC binding_t *get_metamethod_binding(env_t *env, ast_e tag, ast_t *lhs, ast_t *rhs, type_t *ret)
-{
+PUREFUNC binding_t *get_metamethod_binding(env_t *env, ast_e tag, ast_t *lhs, ast_t *rhs, type_t *ret) {
const char *method_name = binop_method_name(tag);
if (!method_name) return NULL;
binding_t *b = get_namespace_binding(env, lhs, method_name);
if (!b || b->type->tag != FunctionType) return NULL;
DeclareMatch(fn, b->type, FunctionType);
if (!type_eq(fn->ret, ret)) return NULL;
- arg_ast_t *args = new(arg_ast_t, .value=lhs, .next=new(arg_ast_t, .value=rhs));
+ arg_ast_t *args = new (arg_ast_t, .value = lhs, .next = new (arg_ast_t, .value = rhs));
return is_valid_call(env, fn->args, args, true) ? b : NULL;
}
-void set_binding(env_t *env, const char *name, type_t *type, Text_t code)
-{
+void set_binding(env_t *env, const char *name, type_t *type, Text_t code) {
assert(name);
- Table$str_set(env->locals, name, new(binding_t, .type=type, .code=code));
+ Table$str_set(env->locals, name, new (binding_t, .type = type, .code = code));
}
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/environment.h b/src/environment.h
index 0bff474d..ca10dbae 100644
--- a/src/environment.h
+++ b/src/environment.h
@@ -46,7 +46,7 @@ typedef struct env_s {
loop_ctx_t *loop_ctx;
deferral_t *deferred;
Closure_t *comprehension_action;
- bool do_source_mapping:1;
+ bool do_source_mapping : 1;
type_t *current_type;
} env_t;
@@ -62,23 +62,21 @@ env_t *fresh_scope(env_t *env);
env_t *for_scope(env_t *env, ast_t *ast);
env_t *with_enum_scope(env_t *env, type_t *t);
env_t *namespace_env(env_t *env, const char *namespace_name);
-#define compiler_err(f, start, end, ...) ({ \
- file_t *_f = f; \
- if (USE_COLOR) \
- fputs("\x1b[31;7;1m ", stderr); \
- if (_f && start && end) \
- fprint_inline(stderr, _f->relative_filename, ":", get_line_number(_f, start), ".", get_line_column(_f, start), ": "); \
- fprint_inline(stderr, __VA_ARGS__); \
- if (USE_COLOR) \
- fputs(" \x1b[m", stderr); \
- fputs("\n\n", stderr); \
- if (_f && start && end) \
- highlight_error(_f, start, end, "\x1b[31;1m", 2, USE_COLOR); \
- if (getenv("TOMO_STACKTRACE")) \
- print_stacktrace(stderr, 1); \
- raise(SIGABRT); \
- exit(1); \
-})
+#define compiler_err(f, start, end, ...) \
+ ({ \
+ file_t *_f = f; \
+ if (USE_COLOR) fputs("\x1b[31;7;1m ", stderr); \
+ if (_f && start && end) \
+ fprint_inline(stderr, _f->relative_filename, ":", get_line_number(_f, start), ".", \
+ get_line_column(_f, start), ": "); \
+ fprint_inline(stderr, __VA_ARGS__); \
+ if (USE_COLOR) fputs(" \x1b[m", stderr); \
+ fputs("\n\n", stderr); \
+ if (_f && start && end) highlight_error(_f, start, end, "\x1b[31;1m", 2, USE_COLOR); \
+ if (getenv("TOMO_STACKTRACE")) print_stacktrace(stderr, 1); \
+ raise(SIGABRT); \
+ exit(1); \
+ })
binding_t *get_binding(env_t *env, const char *name);
binding_t *get_constructor(env_t *env, type_t *t, arg_ast_t *args, bool allow_underscores);
PUREFUNC binding_t *get_metamethod_binding(env_t *env, ast_e tag, ast_t *lhs, ast_t *rhs, type_t *ret);
diff --git a/src/modules.c b/src/modules.c
index 7512e258..d891f64a 100644
--- a/src/modules.c
+++ b/src/modules.c
@@ -14,40 +14,41 @@
#include "stdlib/text.h"
#include "stdlib/types.h"
-#define xsystem(...) ({ int _status = system(String(__VA_ARGS__)); if (!WIFEXITED(_status) || WEXITSTATUS(_status) != 0) errx(1, "Failed to run command: %s", String(__VA_ARGS__)); })
+#define xsystem(...) \
+ ({ \
+ int _status = system(String(__VA_ARGS__)); \
+ if (!WIFEXITED(_status) || WEXITSTATUS(_status) != 0) \
+ errx(1, "Failed to run command: %s", String(__VA_ARGS__)); \
+ })
-static void read_modules_ini(Path_t ini_file, module_info_t *info)
-{
+static void read_modules_ini(Path_t ini_file, module_info_t *info) {
OptionalClosure_t by_line = Path$by_line(ini_file);
if (by_line.fn == NULL) return;
- OptionalText_t (*next_line)(void*) = by_line.fn;
- find_section:;
- for (Text_t line; (line=next_line(by_line.userdata)).length >= 0; ) {
+ OptionalText_t (*next_line)(void *) = by_line.fn;
+find_section:;
+ for (Text_t line; (line = next_line(by_line.userdata)).length >= 0;) {
char *line_str = Text$as_c_string(line);
- if (line_str[0] == '[' && strncmp(line_str+1, info->name, strlen(info->name)) == 0
- && line_str[1+strlen(info->name)] == ']')
+ if (line_str[0] == '[' && strncmp(line_str + 1, info->name, strlen(info->name)) == 0
+ && line_str[1 + strlen(info->name)] == ']')
break;
}
- for (Text_t line; (line=next_line(by_line.userdata)).length >= 0; ) {
+ for (Text_t line; (line = next_line(by_line.userdata)).length >= 0;) {
char *line_str = Text$as_c_string(line);
if (line_str[0] == '[') goto find_section;
- if (!strparse(line_str, "version=", &info->version)
- || !strparse(line_str, "url=", &info->url)
- || !strparse(line_str, "git=", &info->git)
- || !strparse(line_str, "path=", &info->path)
+ if (!strparse(line_str, "version=", &info->version) || !strparse(line_str, "url=", &info->url)
+ || !strparse(line_str, "git=", &info->git) || !strparse(line_str, "path=", &info->path)
|| !strparse(line_str, "revision=", &info->revision))
continue;
}
}
-module_info_t get_module_info(ast_t *use)
-{
+module_info_t get_module_info(ast_t *use) {
static Table_t cache = {};
TypeInfo_t *cache_type = Table$info(Pointer$info("@", &Memory$info), Pointer$info("@", &Memory$info));
module_info_t **cached = Table$get(cache, &use, cache_type);
if (cached) return **cached;
const char *name = Match(use, Use)->path;
- module_info_t *info = new(module_info_t, .name=name);
+ module_info_t *info = new (module_info_t, .name = name);
if (streq(name, "commands")) info->version = "v1.0";
else if (streq(name, "random")) info->version = "v1.0";
else if (streq(name, "base64")) info->version = "v1.0";
@@ -64,16 +65,14 @@ module_info_t get_module_info(ast_t *use)
}
Table$set(&cache, &use, &info, cache_type);
return *info;
-
}
-bool try_install_module(module_info_t mod)
-{
+bool try_install_module(module_info_t mod) {
if (mod.git) {
- OptionalText_t answer = ask(
- Texts(Text("The module \""), Text$from_str(mod.name), Text("\" is not installed.\nDo you want to install it from git URL "),
- Text$from_str(mod.git), Text("? [Y/n] ")),
- true, true);
+ OptionalText_t answer = ask(Texts(Text("The module \""), Text$from_str(mod.name),
+ Text("\" is not installed.\nDo you want to install it from git URL "),
+ Text$from_str(mod.git), Text("? [Y/n] ")),
+ true, true);
if (!(answer.length == 0 || Text$equal_values(answer, Text("Y")) || Text$equal_values(answer, Text("y"))))
return false;
print("Installing ", mod.name, " from git...");
@@ -85,10 +84,10 @@ bool try_install_module(module_info_t mod)
Path$remove(tmpdir, true);
return true;
} else if (mod.url) {
- OptionalText_t answer = ask(
- Texts(Text("The module "), Text$from_str(mod.name), Text(" is not installed.\nDo you want to install it from URL "),
- Text$from_str(mod.url), Text("? [Y/n] ")),
- true, true);
+ OptionalText_t answer = ask(Texts(Text("The module "), Text$from_str(mod.name),
+ Text(" is not installed.\nDo you want to install it from URL "),
+ Text$from_str(mod.url), Text("? [Y/n] ")),
+ true, true);
if (!(answer.length == 0 || Text$equal_values(answer, Text("Y")) || Text$equal_values(answer, Text("y"))))
return false;
@@ -102,22 +101,19 @@ bool try_install_module(module_info_t mod)
const char *extension = p + 1;
Path_t tmpdir = Path$unique_directory(Path("/tmp/tomo-module-XXXXXX"));
xsystem("curl ", mod.url, " -o ", tmpdir);
- if (streq(extension, ".zip"))
- xsystem("unzip ", tmpdir, "/", filename);
- else if (streq(extension, ".tar.gz") || streq(extension, ".tar"))
- xsystem("tar xf ", tmpdir, "/", filename);
- else
- return false;
+ if (streq(extension, ".zip")) xsystem("unzip ", tmpdir, "/", filename);
+ else if (streq(extension, ".tar.gz") || streq(extension, ".tar")) xsystem("tar xf ", tmpdir, "/", filename);
+ else return false;
const char *basename = String(string_slice(filename, strcspn(filename, ".")));
if (mod.path) xsystem("tomo -IL ", tmpdir, "/", basename, "/", mod.path);
else xsystem("tomo -IL ", tmpdir, "/", basename);
Path$remove(tmpdir, true);
return true;
} else if (mod.path) {
- OptionalText_t answer = ask(
- Texts(Text("The module "), Text$from_str(mod.name), Text(" is not installed.\nDo you want to install it from path "),
- Text$from_str(mod.path), Text("? [Y/n] ")),
- true, true);
+ OptionalText_t answer = ask(Texts(Text("The module "), Text$from_str(mod.name),
+ Text(" is not installed.\nDo you want to install it from path "),
+ Text$from_str(mod.path), Text("? [Y/n] ")),
+ true, true);
if (!(answer.length == 0 || Text$equal_values(answer, Text("Y")) || Text$equal_values(answer, Text("y"))))
return false;
diff --git a/src/naming.c b/src/naming.c
index 3bf71597..d0c7cfac 100644
--- a/src/naming.c
+++ b/src/naming.c
@@ -7,59 +7,108 @@
#include "stdlib/paths.h"
#include "stdlib/text.h"
-static const char *c_keywords[] = { // Maintain sorted order:
- "_Alignas", "_Alignof", "_Atomic", "_BitInt", "_Bool", "_Complex", "_Decimal128", "_Decimal32", "_Decimal64", "_Generic",
- "_Imaginary", "_Noreturn", "_Static_assert", "_Thread_local",
- "alignas", "__alignof__", "auto", "bool", "break", "case", "char", "const", "constexpr", "continue", "default", "do", "double",
- "else", "enum", "extern", "false", "float", "for", "goto", "if", "inline", "int", "long", "nullptr", "register", "restrict",
- "return", "short", "signed", "sizeof", "static", "static_assert", "struct", "switch", "thread_local", "true", "typedef",
- "typeof", "typeof_unqual", "union", "unsigned", "void", "volatile", "while",
+static const char *c_keywords[] = {
+ // Maintain sorted order:
+ "_Alignas",
+ "_Alignof",
+ "_Atomic",
+ "_BitInt",
+ "_Bool",
+ "_Complex",
+ "_Decimal128",
+ "_Decimal32",
+ "_Decimal64",
+ "_Generic",
+ "_Imaginary",
+ "_Noreturn",
+ "_Static_assert",
+ "_Thread_local",
+ "alignas",
+ "__alignof__",
+ "auto",
+ "bool",
+ "break",
+ "case",
+ "char",
+ "const",
+ "constexpr",
+ "continue",
+ "default",
+ "do",
+ "double",
+ "else",
+ "enum",
+ "extern",
+ "false",
+ "float",
+ "for",
+ "goto",
+ "if",
+ "inline",
+ "int",
+ "long",
+ "nullptr",
+ "register",
+ "restrict",
+ "return",
+ "short",
+ "signed",
+ "sizeof",
+ "static",
+ "static_assert",
+ "struct",
+ "switch",
+ "thread_local",
+ "true",
+ "typedef",
+ "typeof",
+ "typeof_unqual",
+ "union",
+ "unsigned",
+ "void",
+ "volatile",
+ "while",
};
static CONSTFUNC bool is_keyword(const char *word, size_t len) {
- int64_t lo = 0, hi = sizeof(c_keywords)/sizeof(c_keywords[0])-1;
+ int64_t lo = 0, hi = sizeof(c_keywords) / sizeof(c_keywords[0]) - 1;
while (lo <= hi) {
int64_t mid = (lo + hi) / 2;
int32_t cmp = strncmp(word, c_keywords[mid], len);
- if (cmp == 0)
- return true;
- else if (cmp > 0)
- lo = mid + 1;
- else if (cmp < 0)
- hi = mid - 1;
+ if (cmp == 0) return true;
+ else if (cmp > 0) lo = mid + 1;
+ else if (cmp < 0) hi = mid - 1;
}
return false;
}
-public Text_t valid_c_name(const char *name)
-{
+public
+Text_t valid_c_name(const char *name) {
size_t len = strlen(name);
size_t trailing_underscores = 0;
- while (trailing_underscores < len && name[len-1-trailing_underscores] == '_')
+ while (trailing_underscores < len && name[len - 1 - trailing_underscores] == '_')
trailing_underscores += 1;
- if (is_keyword(name, len-trailing_underscores)) {
+ if (is_keyword(name, len - trailing_underscores)) {
return Texts(Text$from_str(name), Text("_"));
}
return Text$from_str(name);
}
-public Text_t CONSTFUNC namespace_name(env_t *env, namespace_t *ns, Text_t name)
-{
+public
+Text_t CONSTFUNC namespace_name(env_t *env, namespace_t *ns, Text_t name) {
for (; ns; ns = ns->parent)
name = Texts(ns->name, "$", name);
- if (env->id_suffix.length > 0)
- name = Texts(name, env->id_suffix);
+ if (env->id_suffix.length > 0) name = Texts(name, env->id_suffix);
return name;
}
-public Text_t get_id_suffix(const char *filename)
-{
+public
+Text_t get_id_suffix(const char *filename) {
assert(filename);
Path_t path = Path$from_str(filename);
Path_t build_dir = Path$sibling(path, Text(".build"));
if (mkdir(Path$as_c_string(build_dir), 0755) != 0) {
- if (!Path$is_directory(build_dir, true))
- err(1, "Could not make .build directory");
+ if (!Path$is_directory(build_dir, true)) err(1, "Could not make .build directory");
}
Path_t id_file = Path$child(build_dir, Texts(Path$base_name(path), Text$from_str(".id")));
OptionalText_t id = Path$read(id_file);
diff --git a/src/parse.c b/src/parse.c
index 06184b97..9f6f1581 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -14,9 +14,9 @@
#include <unistr.h>
#endif
+#include <signal.h>
#include <unictype.h>
#include <uniname.h>
-#include <signal.h>
#include "ast.h"
#include "stdlib/print.h"
@@ -32,7 +32,7 @@
#endif
static const double RADIANS_PER_DEGREE = 0.0174532925199432957692369076848861271344287188854172545609719144;
-static const char closing[128] = {['(']=')', ['[']=']', ['<']='>', ['{']='}'};
+static const char closing[128] = {['('] = ')', ['['] = ']', ['<'] = '>', ['{'] = '}'};
typedef struct {
file_t *file;
@@ -45,26 +45,40 @@ typedef struct {
#define PARSER(name) ast_t *name(parse_ctx_t *ctx, const char *pos)
int op_tightness[] = {
- [Power]=9,
- [Multiply]=8, [Divide]=8, [Mod]=8, [Mod1]=8,
- [Plus]=7, [Minus]=7,
- [Concat]=6,
- [LeftShift]=5, [RightShift]=5, [UnsignedLeftShift]=5, [UnsignedRightShift]=5,
- [Min]=4, [Max]=4,
- [Equals]=3, [NotEquals]=3,
- [LessThan]=2, [LessThanOrEquals]=2, [GreaterThan]=2, [GreaterThanOrEquals]=2,
- [Compare]=2,
- [And]=1, [Or]=1, [Xor]=1,
+ [Power] = 9,
+ [Multiply] = 8,
+ [Divide] = 8,
+ [Mod] = 8,
+ [Mod1] = 8,
+ [Plus] = 7,
+ [Minus] = 7,
+ [Concat] = 6,
+ [LeftShift] = 5,
+ [RightShift] = 5,
+ [UnsignedLeftShift] = 5,
+ [UnsignedRightShift] = 5,
+ [Min] = 4,
+ [Max] = 4,
+ [Equals] = 3,
+ [NotEquals] = 3,
+ [LessThan] = 2,
+ [LessThanOrEquals] = 2,
+ [GreaterThan] = 2,
+ [GreaterThanOrEquals] = 2,
+ [Compare] = 2,
+ [And] = 1,
+ [Or] = 1,
+ [Xor] = 1,
};
static const char *keywords[] = {
- "C_code", "_max_", "_min_", "and", "assert", "break", "continue", "defer", "deserialize", "do", "else",
- "enum", "extend", "extern", "for", "func", "if", "in", "lang", "mod", "mod1", "no", "none",
- "not", "or", "pass", "return", "skip", "skip", "stop", "struct", "then", "unless", "use", "when",
- "while", "xor", "yes",
+ "C_code", "_max_", "_min_", "and", "assert", "break", "continue", "defer", "deserialize", "do",
+ "else", "enum", "extend", "extern", "for", "func", "if", "in", "lang", "mod",
+ "mod1", "no", "none", "not", "or", "pass", "return", "skip", "skip", "stop",
+ "struct", "then", "unless", "use", "when", "while", "xor", "yes",
};
-enum {NORMAL_FUNCTION=0, EXTERN_FUNCTION=1};
+enum { NORMAL_FUNCTION = 0, EXTERN_FUNCTION = 1 };
static INLINE size_t some_of(const char **pos, const char *allow);
static INLINE size_t some_not(const char **pos, const char *forbid);
@@ -72,8 +86,8 @@ static INLINE size_t spaces(const char **pos);
static INLINE void whitespace(const char **pos);
static INLINE size_t match(const char **pos, const char *target);
static INLINE size_t match_word(const char **pos, const char *word);
-static INLINE const char* get_word(const char **pos);
-static INLINE const char* get_id(const char **pos);
+static INLINE const char *get_word(const char **pos);
+static INLINE const char *get_id(const char **pos);
static INLINE bool comment(const char **pos);
static INLINE bool indent(parse_ctx_t *ctx, const char **pos);
static INLINE ast_e match_binary_operator(const char **pos);
@@ -145,83 +159,83 @@ static PARSER(parse_var);
static PARSER(parse_when);
static PARSER(parse_while);
static PARSER(parse_deserialize);
-static ast_list_t *_parse_text_helper(parse_ctx_t *ctx, const char **out_pos, char open_quote, char close_quote, char open_interp, bool allow_escapes);
+static ast_list_t *_parse_text_helper(parse_ctx_t *ctx, const char **out_pos, char open_quote, char close_quote,
+ char open_interp, bool allow_escapes);
//
// Print a parse error and exit (or use the on_err longjmp)
//
-#define parser_err(ctx, start, end, ...) ({ \
- if (USE_COLOR) \
- fputs("\x1b[31;1;7m", stderr); \
- fprint_inline(stderr, (ctx)->file->relative_filename, ":", get_line_number((ctx)->file, (start)), \
- ".", get_line_column((ctx)->file, (start)), ": ", __VA_ARGS__); \
- if (USE_COLOR) \
- fputs(" \x1b[m", stderr); \
- fputs("\n\n", stderr); \
- highlight_error((ctx)->file, (start), (end), "\x1b[31;1;7m", 2, USE_COLOR); \
- fputs("\n", stderr); \
- if (getenv("TOMO_STACKTRACE")) \
- print_stacktrace(stderr, 1); \
- if ((ctx)->on_err) \
- longjmp(*((ctx)->on_err), 1); \
- raise(SIGABRT); \
- exit(1); \
-})
+#define parser_err(ctx, start, end, ...) \
+ ({ \
+ if (USE_COLOR) fputs("\x1b[31;1;7m", stderr); \
+ fprint_inline(stderr, (ctx)->file->relative_filename, ":", get_line_number((ctx)->file, (start)), ".", \
+ get_line_column((ctx)->file, (start)), ": ", __VA_ARGS__); \
+ if (USE_COLOR) fputs(" \x1b[m", stderr); \
+ fputs("\n\n", stderr); \
+ highlight_error((ctx)->file, (start), (end), "\x1b[31;1;7m", 2, USE_COLOR); \
+ fputs("\n", stderr); \
+ if (getenv("TOMO_STACKTRACE")) print_stacktrace(stderr, 1); \
+ if ((ctx)->on_err) longjmp(*((ctx)->on_err), 1); \
+ raise(SIGABRT); \
+ exit(1); \
+ })
//
// Expect a string (potentially after whitespace) and emit a parser error if it's not there
//
-#define expect_str(ctx, start, pos, target, ...) ({ \
- spaces(pos); \
- if (!match(pos, target)) { \
- if (USE_COLOR) \
- fputs("\x1b[31;1;7m", stderr); \
- parser_err(ctx, start, *pos, __VA_ARGS__); \
- } \
- char _lastchar = target[strlen(target)-1]; \
- if (isalpha(_lastchar) || isdigit(_lastchar) || _lastchar == '_') { \
- if (is_xid_continue_next(*pos)) { \
- if (USE_COLOR) \
- fputs("\x1b[31;1;7m", stderr); \
- parser_err(ctx, start, *pos, __VA_ARGS__); \
- } \
- } \
-})
+#define expect_str(ctx, start, pos, target, ...) \
+ ({ \
+ spaces(pos); \
+ if (!match(pos, target)) { \
+ if (USE_COLOR) fputs("\x1b[31;1;7m", stderr); \
+ parser_err(ctx, start, *pos, __VA_ARGS__); \
+ } \
+ char _lastchar = target[strlen(target) - 1]; \
+ if (isalpha(_lastchar) || isdigit(_lastchar) || _lastchar == '_') { \
+ if (is_xid_continue_next(*pos)) { \
+ if (USE_COLOR) fputs("\x1b[31;1;7m", stderr); \
+ parser_err(ctx, start, *pos, __VA_ARGS__); \
+ } \
+ } \
+ })
//
// Helper for matching closing parens with good error messages
//
-#define expect_closing(ctx, pos, close_str, ...) ({ \
- const char *_start = *pos; \
- spaces(pos); \
- if (!match(pos, (close_str))) { \
- const char *_eol = strchr(*pos, '\n'); \
- const char *_next = strstr(*pos, (close_str)); \
- const char *_end = _eol < _next ? _eol : _next; \
- if (USE_COLOR) \
- fputs("\x1b[31;1;7m", stderr); \
- parser_err(ctx, _start, _end, __VA_ARGS__); \
- } \
-})
-
-#define expect(ctx, start, pos, parser, ...) ({ \
- const char **_pos = pos; \
- spaces(_pos); \
- __typeof(parser(ctx, *_pos)) _result = parser(ctx, *_pos); \
- if (!_result) { \
- if (USE_COLOR) \
- fputs("\x1b[31;1;7m", stderr); \
- parser_err(ctx, start, *_pos, __VA_ARGS__); \
- } \
- *_pos = _result->end; \
- _result; })
-
-#define optional(ctx, pos, parser) ({ \
- const char **_pos = pos; \
- spaces(_pos); \
- __typeof(parser(ctx, *_pos)) _result = parser(ctx, *_pos); \
- if (_result) *_pos = _result->end; \
- _result; })
+#define expect_closing(ctx, pos, close_str, ...) \
+ ({ \
+ const char *_start = *pos; \
+ spaces(pos); \
+ if (!match(pos, (close_str))) { \
+ const char *_eol = strchr(*pos, '\n'); \
+ const char *_next = strstr(*pos, (close_str)); \
+ const char *_end = _eol < _next ? _eol : _next; \
+ if (USE_COLOR) fputs("\x1b[31;1;7m", stderr); \
+ parser_err(ctx, _start, _end, __VA_ARGS__); \
+ } \
+ })
+
+#define expect(ctx, start, pos, parser, ...) \
+ ({ \
+ const char **_pos = pos; \
+ spaces(_pos); \
+ __typeof(parser(ctx, *_pos)) _result = parser(ctx, *_pos); \
+ if (!_result) { \
+ if (USE_COLOR) fputs("\x1b[31;1;7m", stderr); \
+ parser_err(ctx, start, *_pos, __VA_ARGS__); \
+ } \
+ *_pos = _result->end; \
+ _result; \
+ })
+
+#define optional(ctx, pos, parser) \
+ ({ \
+ const char **_pos = pos; \
+ spaces(_pos); \
+ __typeof(parser(ctx, *_pos)) _result = parser(ctx, *_pos); \
+ if (_result) *_pos = _result->end; \
+ _result; \
+ })
//
// Convert an escape sequence like \n to a string
@@ -233,7 +247,8 @@ static ast_list_t *_parse_text_helper(parse_ctx_t *ctx, const char **out_pos, ch
static const char *unescape(parse_ctx_t *ctx, const char **out) {
const char **endpos = out;
const char *escape = *out;
- static const char *unescapes[256] = {['a']="\a",['b']="\b",['e']="\x1b",['f']="\f",['n']="\n",['r']="\r",['t']="\t",['v']="\v",['_']=" "};
+ static const char *unescapes[256] = {['a'] = "\a", ['b'] = "\b", ['e'] = "\x1b", ['f'] = "\f", ['n'] = "\n",
+ ['r'] = "\r", ['t'] = "\t", ['v'] = "\v", ['_'] = " "};
assert(*escape == '\\');
if (unescapes[(int)escape[1]]) {
*endpos = escape + 2;
@@ -241,16 +256,14 @@ static const char *unescape(parse_ctx_t *ctx, const char **out) {
} else if (escape[1] == '[') {
// ANSI Control Sequence Indicator: \033 [ ... m
size_t len = strcspn(&escape[2], "\r\n]");
- if (escape[2+len] != ']')
- parser_err(ctx, escape, escape + 2 + len, "Missing closing ']'");
+ if (escape[2 + len] != ']') parser_err(ctx, escape, escape + 2 + len, "Missing closing ']'");
*endpos = escape + 3 + len;
return String("\033[", string_slice(&escape[2], len), "m");
} else if (escape[1] == '{') {
// Unicode codepoints by name
size_t len = strcspn(&escape[2], "\r\n}");
- if (escape[2+len] != '}')
- parser_err(ctx, escape, escape + 2 + len, "Missing closing '}'");
- char name[len+1];
+ if (escape[2 + len] != '}') parser_err(ctx, escape, escape + 2 + len, "Missing closing '}'");
+ char name[len + 1];
memcpy(name, &escape[2], len);
name[len] = '\0';
@@ -260,25 +273,24 @@ static const char *unescape(parse_ctx_t *ctx, const char **out) {
}
// Unicode codepoints by hex
char *endptr = NULL;
- long codepoint = strtol(name+1, &endptr, 16);
+ long codepoint = strtol(name + 1, &endptr, 16);
uint32_t ustr[2] = {codepoint, 0};
size_t bufsize = 8;
uint8_t buf[bufsize];
(void)u32_to_u8(ustr, bufsize, buf, &bufsize);
*endpos = escape + 3 + len;
- return GC_strndup((char*)buf, bufsize);
+ return GC_strndup((char *)buf, bufsize);
}
- look_up_unicode_name:;
+ look_up_unicode_name:;
uint32_t codepoint = unicode_name_character(name);
if (codepoint == UNINAME_INVALID)
- parser_err(ctx, escape, escape + 3 + len,
- "Invalid unicode codepoint name: ", quoted(name));
+ parser_err(ctx, escape, escape + 3 + len, "Invalid unicode codepoint name: ", quoted(name));
*endpos = escape + 3 + len;
char *str = GC_MALLOC_ATOMIC(16);
size_t u8_len = 16;
- (void)u32_to_u8(&codepoint, 1, (uint8_t*)str, &u8_len);
+ (void)u32_to_u8(&codepoint, 1, (uint8_t *)str, &u8_len);
str[u8_len] = '\0';
return str;
} else if (escape[1] == 'x' && escape[2] && escape[3]) {
@@ -287,14 +299,15 @@ static const char *unescape(parse_ctx_t *ctx, const char **out) {
char c = (char)strtol(buf, NULL, 16);
*endpos = escape + 4;
return GC_strndup(&c, 1);
- } else if ('0' <= escape[1] && escape[1] <= '7' && '0' <= escape[2] && escape[2] <= '7' && '0' <= escape[3] && escape[3] <= '7') {
+ } else if ('0' <= escape[1] && escape[1] <= '7' && '0' <= escape[2] && escape[2] <= '7' && '0' <= escape[3]
+ && escape[3] <= '7') {
char buf[] = {escape[1], escape[2], escape[3], 0};
char c = (char)strtol(buf, NULL, 8);
*endpos = escape + 4;
return GC_strndup(&c, 1);
} else {
*endpos = escape + 2;
- return GC_strndup(escape+1, 1);
+ return GC_strndup(escape + 1, 1);
}
}
#ifdef __GNUC__
@@ -302,8 +315,7 @@ static const char *unescape(parse_ctx_t *ctx, const char **out) {
#endif
// Indent is in number of spaces (assuming that \t is 4 spaces)
-PUREFUNC static INLINE int64_t get_indent(parse_ctx_t *ctx, const char *pos)
-{
+PUREFUNC static INLINE int64_t get_indent(parse_ctx_t *ctx, const char *pos) {
int64_t line_num = get_line_number(ctx->file, pos);
const char *line = get_line(ctx->file, line_num);
if (line == NULL) {
@@ -311,12 +323,14 @@ PUREFUNC static INLINE int64_t get_indent(parse_ctx_t *ctx, const char *pos)
} else if (*line == ' ') {
int64_t spaces = (int64_t)strspn(line, " ");
if (line[spaces] == '\t')
- parser_err(ctx, line + spaces, line + spaces + 1, "This is a tab following spaces, and you can't mix tabs and spaces");
+ parser_err(ctx, line + spaces, line + spaces + 1,
+ "This is a tab following spaces, and you can't mix tabs and spaces");
return spaces;
} else if (*line == '\t') {
int64_t indent = (int64_t)strspn(line, "\t");
if (line[indent] == ' ')
- parser_err(ctx, line + indent, line + indent + 1, "This is a space following tabs, and you can't mix tabs and spaces");
+ parser_err(ctx, line + indent, line + indent + 1,
+ "This is a space following tabs, and you can't mix tabs and spaces");
return indent * SPACES_PER_INDENT;
} else {
return 0;
@@ -338,9 +352,7 @@ size_t some_not(const char **pos, const char *forbid) {
return len;
}
-size_t spaces(const char **pos) {
- return some_of(pos, " \t");
-}
+size_t spaces(const char **pos) { return some_of(pos, " \t"); }
void whitespace(const char **pos) {
while (some_of(pos, " \t\r\n") || comment(pos))
@@ -349,23 +361,21 @@ void whitespace(const char **pos) {
size_t match(const char **pos, const char *target) {
size_t len = strlen(target);
- if (strncmp(*pos, target, len) != 0)
- return 0;
+ if (strncmp(*pos, target, len) != 0) return 0;
*pos += len;
return len;
}
static INLINE bool is_xid_continue_next(const char *pos) {
ucs4_t point = 0;
- u8_next(&point, (const uint8_t*)pos);
+ u8_next(&point, (const uint8_t *)pos);
return uc_is_property_xid_continue(point);
}
size_t match_word(const char **out, const char *word) {
const char *pos = *out;
spaces(&pos);
- if (!match(&pos, word) || is_xid_continue_next(pos))
- return 0;
+ if (!match(&pos, word) || is_xid_continue_next(pos)) return 0;
*out = pos;
return strlen(word);
@@ -374,31 +384,26 @@ size_t match_word(const char **out, const char *word) {
const char *get_word(const char **inout) {
const char *word = *inout;
spaces(&word);
- const uint8_t *pos = (const uint8_t*)word;
+ const uint8_t *pos = (const uint8_t *)word;
ucs4_t point;
pos = u8_next(&point, pos);
- if (!uc_is_property_xid_start(point) && point != '_')
- return NULL;
+ if (!uc_is_property_xid_start(point) && point != '_') return NULL;
for (const uint8_t *next; (next = u8_next(&point, pos)); pos = next) {
- if (!uc_is_property_xid_continue(point))
- break;
+ if (!uc_is_property_xid_continue(point)) break;
}
- *inout = (const char*)pos;
- return GC_strndup(word, (size_t)((const char*)pos - word));
+ *inout = (const char *)pos;
+ return GC_strndup(word, (size_t)((const char *)pos - word));
}
static CONSTFUNC bool is_keyword(const char *word) {
- int64_t lo = 0, hi = sizeof(keywords)/sizeof(keywords[0])-1;
+ int64_t lo = 0, hi = sizeof(keywords) / sizeof(keywords[0]) - 1;
while (lo <= hi) {
int64_t mid = (lo + hi) / 2;
int32_t cmp = strcmp(word, keywords[mid]);
- if (cmp == 0)
- return true;
- else if (cmp > 0)
- lo = mid + 1;
- else if (cmp < 0)
- hi = mid - 1;
+ if (cmp == 0) return true;
+ else if (cmp > 0) lo = mid + 1;
+ else if (cmp < 0) hi = mid - 1;
}
return false;
}
@@ -406,15 +411,12 @@ static CONSTFUNC bool is_keyword(const char *word) {
const char *get_id(const char **inout) {
const char *pos = *inout;
const char *word = get_word(&pos);
- if (!word || is_keyword(word))
- return NULL;
+ if (!word || is_keyword(word)) return NULL;
*inout = pos;
return word;
}
-static const char *eol(const char *str) {
- return str + strcspn(str, "\r\n");
-}
+static const char *eol(const char *str) { return str + strcspn(str, "\r\n"); }
bool comment(const char **pos) {
if ((*pos)[0] == '#') {
@@ -430,11 +432,9 @@ bool indent(parse_ctx_t *ctx, const char **out) {
int64_t starting_indent = get_indent(ctx, pos);
whitespace(&pos);
const char *next_line = get_line(ctx->file, get_line_number(ctx->file, pos));
- if (next_line <= *out)
- return false;
+ if (next_line <= *out) return false;
- if (get_indent(ctx, next_line) != starting_indent + SPACES_PER_INDENT)
- return false;
+ if (get_indent(ctx, next_line) != starting_indent + SPACES_PER_INDENT) return false;
*out = next_line + strspn(next_line, " \t");
return true;
@@ -486,8 +486,7 @@ PARSER(parse_parens) {
expect_closing(ctx, &pos, ")", "I wasn't able to parse the rest of this expression");
// Update the span to include the parens:
- return new(ast_t, .file=(ctx)->file, .start=start, .end=pos,
- .tag=expr->tag, .__data=expr->__data);
+ return new (ast_t, .file = (ctx)->file, .start = start, .end = pos, .tag = expr->tag, .__data = expr->__data);
}
PARSER(parse_int) {
@@ -505,7 +504,7 @@ PARSER(parse_int) {
}
char *str = GC_MALLOC_ATOMIC((size_t)(pos - start) + 1);
memset(str, 0, (size_t)(pos - start) + 1);
- for (char *src = (char*)start, *dest = str; src < pos; ++src) {
+ for (char *src = (char *)start, *dest = str; src < pos; ++src) {
if (*src != '_') *(dest++) = *src;
}
@@ -514,13 +513,13 @@ PARSER(parse_int) {
if (match(&pos, "%")) {
double n = strtod(str, NULL) / 100.;
- return NewAST(ctx->file, start, pos, Num, .n=n);
+ return NewAST(ctx->file, start, pos, Num, .n = n);
} else if (match(&pos, "deg")) {
double n = strtod(str, NULL) * RADIANS_PER_DEGREE;
- return NewAST(ctx->file, start, pos, Num, .n=n);
+ return NewAST(ctx->file, start, pos, Num, .n = n);
}
- return NewAST(ctx->file, start, pos, Int, .str=str);
+ return NewAST(ctx->file, start, pos, Int, .str = str);
}
type_ast_t *parse_table_type(parse_ctx_t *ctx, const char *pos) {
@@ -541,11 +540,13 @@ type_ast_t *parse_table_type(parse_ctx_t *ctx, const char *pos) {
ast_t *default_value = NULL;
if (match(&pos, ";") && match_word(&pos, "default")) {
expect_str(ctx, pos, &pos, "=", "I expected an '=' here");
- default_value = expect(ctx, start, &pos, parse_extended_expr, "I couldn't parse the default value for this table");
+ default_value =
+ expect(ctx, start, &pos, parse_extended_expr, "I couldn't parse the default value for this table");
}
whitespace(&pos);
expect_closing(ctx, &pos, "}", "I wasn't able to parse the rest of this table type");
- return NewTypeAST(ctx->file, start, pos, TableTypeAST, .key=key_type, .value=value_type, .default_value=default_value);
+ return NewTypeAST(ctx->file, start, pos, TableTypeAST, .key = key_type, .value = value_type,
+ .default_value = default_value);
}
type_ast_t *parse_set_type(parse_ctx_t *ctx, const char *pos) {
@@ -557,7 +558,7 @@ type_ast_t *parse_set_type(parse_ctx_t *ctx, const char *pos) {
pos = item_type->end;
whitespace(&pos);
expect_closing(ctx, &pos, "|", "I wasn't able to parse the rest of this set type");
- return NewTypeAST(ctx->file, start, pos, SetTypeAST, .item=item_type);
+ return NewTypeAST(ctx->file, start, pos, SetTypeAST, .item = item_type);
}
type_ast_t *parse_func_type(parse_ctx_t *ctx, const char *pos) {
@@ -569,35 +570,31 @@ type_ast_t *parse_func_type(parse_ctx_t *ctx, const char *pos) {
spaces(&pos);
type_ast_t *ret = match(&pos, "->") ? optional(ctx, &pos, parse_type) : NULL;
expect_closing(ctx, &pos, ")", "I wasn't able to parse the rest of this function type");
- return NewTypeAST(ctx->file, start, pos, FunctionTypeAST, .args=args, .ret=ret);
+ return NewTypeAST(ctx->file, start, pos, FunctionTypeAST, .args = args, .ret = ret);
}
type_ast_t *parse_list_type(parse_ctx_t *ctx, const char *pos) {
const char *start = pos;
if (!match(&pos, "[")) return NULL;
- type_ast_t *type = expect(ctx, start, &pos, parse_type,
- "I couldn't parse a list item type after this point");
+ type_ast_t *type = expect(ctx, start, &pos, parse_type, "I couldn't parse a list item type after this point");
expect_closing(ctx, &pos, "]", "I wasn't able to parse the rest of this list type");
- return NewTypeAST(ctx->file, start, pos, ListTypeAST, .item=type);
+ return NewTypeAST(ctx->file, start, pos, ListTypeAST, .item = type);
}
type_ast_t *parse_pointer_type(parse_ctx_t *ctx, const char *pos) {
const char *start = pos;
bool is_stack;
- if (match(&pos, "@"))
- is_stack = false;
- else if (match(&pos, "&"))
- is_stack = true;
- else
- return NULL;
+ if (match(&pos, "@")) is_stack = false;
+ else if (match(&pos, "&")) is_stack = true;
+ else return NULL;
spaces(&pos);
- type_ast_t *type = expect(ctx, start, &pos, parse_non_optional_type,
- "I couldn't parse a pointer type after this point");
- type_ast_t *ptr_type = NewTypeAST(ctx->file, start, pos, PointerTypeAST, .pointed=type, .is_stack=is_stack);
+ type_ast_t *type =
+ expect(ctx, start, &pos, parse_non_optional_type, "I couldn't parse a pointer type after this point");
+ type_ast_t *ptr_type = NewTypeAST(ctx->file, start, pos, PointerTypeAST, .pointed = type, .is_stack = is_stack);
spaces(&pos);
while (match(&pos, "?"))
- ptr_type = NewTypeAST(ctx->file, start, pos, OptionalTypeAST, .type=ptr_type);
+ ptr_type = NewTypeAST(ctx->file, start, pos, OptionalTypeAST, .type = ptr_type);
return ptr_type;
}
@@ -614,20 +611,15 @@ type_ast_t *parse_type_name(parse_ctx_t *ctx, const char *pos) {
id = String(id, ".", next_id);
pos = next;
}
- return NewTypeAST(ctx->file, start, pos, VarTypeAST, .name=id);
+ return NewTypeAST(ctx->file, start, pos, VarTypeAST, .name = id);
}
type_ast_t *parse_non_optional_type(parse_ctx_t *ctx, const char *pos) {
const char *start = pos;
type_ast_t *type = NULL;
- bool success = (false
- || (type=parse_pointer_type(ctx, pos))
- || (type=parse_list_type(ctx, pos))
- || (type=parse_table_type(ctx, pos))
- || (type=parse_set_type(ctx, pos))
- || (type=parse_type_name(ctx, pos))
- || (type=parse_func_type(ctx, pos))
- );
+ bool success = (false || (type = parse_pointer_type(ctx, pos)) || (type = parse_list_type(ctx, pos))
+ || (type = parse_table_type(ctx, pos)) || (type = parse_set_type(ctx, pos))
+ || (type = parse_type_name(ctx, pos)) || (type = parse_func_type(ctx, pos)));
if (!success && match(&pos, "(")) {
whitespace(&pos);
type = optional(ctx, &pos, parse_type);
@@ -648,7 +640,7 @@ type_ast_t *parse_type(parse_ctx_t *ctx, const char *pos) {
pos = type->end;
spaces(&pos);
while (match(&pos, "?"))
- type = NewTypeAST(ctx->file, start, pos, OptionalTypeAST, .type=type);
+ type = NewTypeAST(ctx->file, start, pos, OptionalTypeAST, .type = type);
return type;
}
@@ -659,21 +651,17 @@ PARSER(parse_num) {
else if (*pos == '.' && !isdigit(pos[1])) return NULL;
size_t len = strspn(pos, "0123456789_");
- if (strncmp(pos+len, "..", 2) == 0)
- return NULL;
- else if (pos[len] == '.')
- len += 1 + strspn(pos + len + 1, "0123456789");
- else if (pos[len] != 'e' && pos[len] != 'f' && pos[len] != '%')
- return NULL;
+ if (strncmp(pos + len, "..", 2) == 0) return NULL;
+ else if (pos[len] == '.') len += 1 + strspn(pos + len + 1, "0123456789");
+ else if (pos[len] != 'e' && pos[len] != 'f' && pos[len] != '%') return NULL;
if (pos[len] == 'e') {
len += 1;
- if (pos[len] == '-')
- len += 1;
+ if (pos[len] == '-') len += 1;
len += strspn(pos + len, "0123456789_");
}
- char *buf = GC_MALLOC_ATOMIC(len+1);
- memset(buf, 0, len+1);
- for (char *src = (char*)pos, *dest = buf; src < pos+len; ++src) {
+ char *buf = GC_MALLOC_ATOMIC(len + 1);
+ memset(buf, 0, len + 1);
+ for (char *src = (char *)pos, *dest = buf; src < pos + len; ++src) {
if (*src != '_') *(dest++) = *src;
}
double d = strtod(buf, NULL);
@@ -681,22 +669,18 @@ PARSER(parse_num) {
if (negative) d *= -1;
- if (match(&pos, "%"))
- d /= 100.;
- else if (match(&pos, "deg"))
- d *= RADIANS_PER_DEGREE;
+ if (match(&pos, "%")) d /= 100.;
+ else if (match(&pos, "deg")) d *= RADIANS_PER_DEGREE;
- return NewAST(ctx->file, start, pos, Num, .n=d);
+ return NewAST(ctx->file, start, pos, Num, .n = d);
}
static INLINE bool match_separator(const char **pos) { // Either comma or newline
const char *p = *pos;
int separators = 0;
for (;;) {
- if (some_of(&p, "\r\n,"))
- ++separators;
- else if (!comment(&p) && !some_of(&p, " \t"))
- break;
+ if (some_of(&p, "\r\n,")) ++separators;
+ else if (!comment(&p) && !some_of(&p, " \t")) break;
}
if (separators > 0) {
*pos = p;
@@ -722,15 +706,14 @@ PARSER(parse_list) {
pos = suffixed->end;
suffixed = parse_comprehension_suffix(ctx, item);
}
- items = new(ast_list_t, .ast=item, .next=items);
- if (!match_separator(&pos))
- break;
+ items = new (ast_list_t, .ast = item, .next = items);
+ if (!match_separator(&pos)) break;
}
whitespace(&pos);
expect_closing(ctx, &pos, "]", "I wasn't able to parse the rest of this list");
REVERSE_LIST(items);
- return NewAST(ctx->file, start, pos, List, .items=items);
+ return NewAST(ctx->file, start, pos, List, .items = items);
}
PARSER(parse_table) {
@@ -746,17 +729,16 @@ PARSER(parse_table) {
if (!key) break;
whitespace(&pos);
if (!match(&pos, "=")) return NULL;
- ast_t *value = expect(ctx, pos-1, &pos, parse_expr, "I couldn't parse the value for this table entry");
- ast_t *entry = NewAST(ctx->file, entry_start, pos, TableEntry, .key=key, .value=value);
+ ast_t *value = expect(ctx, pos - 1, &pos, parse_expr, "I couldn't parse the value for this table entry");
+ ast_t *entry = NewAST(ctx->file, entry_start, pos, TableEntry, .key = key, .value = value);
ast_t *suffixed = parse_comprehension_suffix(ctx, entry);
while (suffixed) {
entry = suffixed;
pos = suffixed->end;
suffixed = parse_comprehension_suffix(ctx, entry);
}
- entries = new(ast_list_t, .ast=entry, .next=entries);
- if (!match_separator(&pos))
- break;
+ entries = new (ast_list_t, .ast = entry, .next = entries);
+ if (!match_separator(&pos)) break;
}
REVERSE_LIST(entries);
@@ -771,14 +753,12 @@ PARSER(parse_table) {
if (match_word(&pos, "fallback")) {
whitespace(&pos);
if (!match(&pos, "=")) parser_err(ctx, attr_start, pos, "I expected an '=' after 'fallback'");
- if (fallback)
- parser_err(ctx, attr_start, pos, "This table already has a fallback");
+ if (fallback) parser_err(ctx, attr_start, pos, "This table already has a fallback");
fallback = expect(ctx, attr_start, &pos, parse_expr, "I expected a fallback table");
} else if (match_word(&pos, "default")) {
whitespace(&pos);
if (!match(&pos, "=")) parser_err(ctx, attr_start, pos, "I expected an '=' after 'default'");
- if (default_value)
- parser_err(ctx, attr_start, pos, "This table already has a default");
+ if (default_value) parser_err(ctx, attr_start, pos, "This table already has a default");
default_value = expect(ctx, attr_start, &pos, parse_expr, "I expected a default value");
} else {
break;
@@ -791,13 +771,13 @@ PARSER(parse_table) {
whitespace(&pos);
expect_closing(ctx, &pos, "}", "I wasn't able to parse the rest of this table");
- return NewAST(ctx->file, start, pos, Table, .default_value=default_value, .entries=entries, .fallback=fallback);
+ return NewAST(ctx->file, start, pos, Table, .default_value = default_value, .entries = entries,
+ .fallback = fallback);
}
PARSER(parse_set) {
const char *start = pos;
- if (match(&pos, "||"))
- return NewAST(ctx->file, start, pos, Set);
+ if (match(&pos, "||")) return NewAST(ctx->file, start, pos, Set);
if (!match(&pos, "|")) return NULL;
whitespace(&pos);
@@ -813,9 +793,8 @@ PARSER(parse_set) {
pos = suffixed->end;
suffixed = parse_comprehension_suffix(ctx, item);
}
- items = new(ast_list_t, .ast=item, .next=items);
- if (!match_separator(&pos))
- break;
+ items = new (ast_list_t, .ast = item, .next = items);
+ if (!match_separator(&pos)) break;
}
REVERSE_LIST(items);
@@ -823,7 +802,7 @@ PARSER(parse_set) {
whitespace(&pos);
expect_closing(ctx, &pos, "|", "I wasn't able to parse the rest of this set");
- return NewAST(ctx->file, start, pos, Set, .items=items);
+ return NewAST(ctx->file, start, pos, Set, .items = items);
}
ast_t *parse_field_suffix(parse_ctx_t *ctx, ast_t *lhs) {
@@ -834,49 +813,41 @@ ast_t *parse_field_suffix(parse_ctx_t *ctx, ast_t *lhs) {
if (*pos == '.') return NULL;
whitespace(&pos);
bool dollar = match(&pos, "$");
- const char* field = get_id(&pos);
+ const char *field = get_id(&pos);
if (!field) return NULL;
if (dollar) field = String("$", field);
- return NewAST(ctx->file, lhs->start, pos, FieldAccess, .fielded=lhs, .field=field);
+ return NewAST(ctx->file, lhs->start, pos, FieldAccess, .fielded = lhs, .field = field);
}
ast_t *parse_optional_suffix(parse_ctx_t *ctx, ast_t *lhs) {
if (!lhs) return NULL;
const char *pos = lhs->end;
- if (match(&pos, "?"))
- return NewAST(ctx->file, lhs->start, pos, Optional, .value=lhs);
- else
- return NULL;
+ if (match(&pos, "?")) return NewAST(ctx->file, lhs->start, pos, Optional, .value = lhs);
+ else return NULL;
}
ast_t *parse_non_optional_suffix(parse_ctx_t *ctx, ast_t *lhs) {
if (!lhs) return NULL;
const char *pos = lhs->end;
- if (match(&pos, "!"))
- return NewAST(ctx->file, lhs->start, pos, NonOptional, .value=lhs);
- else
- return NULL;
+ if (match(&pos, "!")) return NewAST(ctx->file, lhs->start, pos, NonOptional, .value = lhs);
+ else return NULL;
}
PARSER(parse_reduction) {
const char *start = pos;
if (!match(&pos, "(")) return NULL;
-
+
whitespace(&pos);
ast_e op = match_binary_operator(&pos);
if (op == Unknown) return NULL;
- ast_t *key = NewAST(ctx->file, pos, pos, Var, .name="$");
- for (bool progress = true; progress; ) {
+ ast_t *key = NewAST(ctx->file, pos, pos, Var, .name = "$");
+ for (bool progress = true; progress;) {
ast_t *new_term;
- progress = (false
- || (new_term=parse_index_suffix(ctx, key))
- || (new_term=parse_method_call_suffix(ctx, key))
- || (new_term=parse_field_suffix(ctx, key))
- || (new_term=parse_fncall_suffix(ctx, key))
- || (new_term=parse_optional_suffix(ctx, key))
- || (new_term=parse_non_optional_suffix(ctx, key))
- );
+ progress =
+ (false || (new_term = parse_index_suffix(ctx, key)) || (new_term = parse_method_call_suffix(ctx, key))
+ || (new_term = parse_field_suffix(ctx, key)) || (new_term = parse_fncall_suffix(ctx, key))
+ || (new_term = parse_optional_suffix(ctx, key)) || (new_term = parse_non_optional_suffix(ctx, key)));
if (progress) key = new_term;
}
if (key && key->tag == Var) key = NULL;
@@ -897,7 +868,7 @@ PARSER(parse_reduction) {
whitespace(&pos);
expect_closing(ctx, &pos, ")", "I wasn't able to parse the rest of this reduction");
- return NewAST(ctx->file, start, pos, Reduction, .iter=iter, .op=op, .key=key);
+ return NewAST(ctx->file, start, pos, Reduction, .iter = iter, .op = op, .key = key);
}
ast_t *parse_index_suffix(parse_ctx_t *ctx, ast_t *lhs) {
@@ -910,7 +881,7 @@ ast_t *parse_index_suffix(parse_ctx_t *ctx, ast_t *lhs) {
whitespace(&pos);
bool unchecked = match(&pos, ";") && (spaces(&pos), match_word(&pos, "unchecked") != 0);
expect_closing(ctx, &pos, "]", "I wasn't able to parse the rest of this index");
- return NewAST(ctx->file, start, pos, Index, .indexed=lhs, .index=index, .unchecked=unchecked);
+ return NewAST(ctx->file, start, pos, Index, .indexed = lhs, .index = index, .unchecked = unchecked);
}
ast_t *parse_comprehension_suffix(parse_ctx_t *ctx, ast_t *expr) {
@@ -924,12 +895,10 @@ ast_t *parse_comprehension_suffix(parse_ctx_t *ctx, ast_t *expr) {
ast_list_t *vars = NULL;
for (;;) {
ast_t *var = optional(ctx, &pos, parse_var);
- if (var)
- vars = new(ast_list_t, .ast=var, .next=vars);
+ if (var) vars = new (ast_list_t, .ast = var, .next = vars);
spaces(&pos);
- if (!match(&pos, ","))
- break;
+ if (!match(&pos, ",")) break;
}
REVERSE_LIST(vars);
@@ -940,13 +909,13 @@ ast_t *parse_comprehension_suffix(parse_ctx_t *ctx, ast_t *expr) {
ast_t *filter = NULL;
if (match_word(&next_pos, "if")) {
pos = next_pos;
- filter = expect(ctx, pos-2, &pos, parse_expr, "I expected a condition for this 'if'");
+ filter = expect(ctx, pos - 2, &pos, parse_expr, "I expected a condition for this 'if'");
} else if (match_word(&next_pos, "unless")) {
pos = next_pos;
- filter = expect(ctx, pos-2, &pos, parse_expr, "I expected a condition for this 'unless'");
+ filter = expect(ctx, pos - 2, &pos, parse_expr, "I expected a condition for this 'unless'");
filter = WrapAST(filter, Not, filter);
}
- return NewAST(ctx->file, start, pos, Comprehension, .expr=expr, .vars=vars, .iter=iter, .filter=filter);
+ return NewAST(ctx->file, start, pos, Comprehension, .expr = expr, .vars = vars, .iter = iter, .filter = filter);
}
ast_t *parse_optional_conditional_suffix(parse_ctx_t *ctx, ast_t *stmt) {
@@ -955,12 +924,12 @@ ast_t *parse_optional_conditional_suffix(parse_ctx_t *ctx, ast_t *stmt) {
const char *start = stmt->start;
const char *pos = stmt->end;
if (match_word(&pos, "if")) {
- ast_t *condition = expect(ctx, pos-2, &pos, parse_expr, "I expected a condition for this 'if'");
- return NewAST(ctx->file, start, pos, If, .condition=condition, .body=stmt);
+ ast_t *condition = expect(ctx, pos - 2, &pos, parse_expr, "I expected a condition for this 'if'");
+ return NewAST(ctx->file, start, pos, If, .condition = condition, .body = stmt);
} else if (match_word(&pos, "unless")) {
- ast_t *condition = expect(ctx, pos-2, &pos, parse_expr, "I expected a condition for this 'unless'");
+ ast_t *condition = expect(ctx, pos - 2, &pos, parse_expr, "I expected a condition for this 'unless'");
condition = WrapAST(condition, Not, condition);
- return NewAST(ctx->file, start, pos, If, .condition=condition, .body=stmt);
+ return NewAST(ctx->file, start, pos, If, .condition = condition, .body = stmt);
} else {
return stmt;
}
@@ -972,22 +941,17 @@ PARSER(parse_if) {
int64_t starting_indent = get_indent(ctx, pos);
bool unless;
- if (match_word(&pos, "if"))
- unless = false;
- else if (match_word(&pos, "unless"))
- unless = true;
- else
- return NULL;
+ if (match_word(&pos, "if")) unless = false;
+ else if (match_word(&pos, "unless")) unless = true;
+ else return NULL;
ast_t *condition = unless ? NULL : optional(ctx, &pos, parse_declaration);
- if (!condition)
- condition = expect(ctx, start, &pos, parse_expr, "I expected to find a condition for this 'if'");
+ if (!condition) condition = expect(ctx, start, &pos, parse_expr, "I expected to find a condition for this 'if'");
- if (unless)
- condition = WrapAST(condition, Not, condition);
+ if (unless) condition = WrapAST(condition, Not, condition);
(void)match_word(&pos, "then"); // Optional 'then'
- ast_t *body = expect(ctx, start, &pos, parse_block, "I expected a body for this 'if' statement");
+ ast_t *body = expect(ctx, start, &pos, parse_block, "I expected a body for this 'if' statement");
const char *tmp = pos;
whitespace(&tmp);
@@ -997,10 +961,9 @@ PARSER(parse_if) {
pos = tmp;
spaces(&pos);
else_body = optional(ctx, &pos, parse_if);
- if (!else_body)
- else_body = expect(ctx, else_start, &pos, parse_block, "I expected a body for this 'else'");
+ if (!else_body) else_body = expect(ctx, else_start, &pos, parse_block, "I expected a body for this 'else'");
}
- return NewAST(ctx->file, start, pos, If, .condition=condition, .body=body, .else_body=else_body);
+ return NewAST(ctx->file, start, pos, If, .condition = condition, .body = body, .else_body = else_body);
}
PARSER(parse_when) {
@@ -1008,12 +971,10 @@ PARSER(parse_when) {
const char *start = pos;
int64_t starting_indent = get_indent(ctx, pos);
- if (!match_word(&pos, "when"))
- return NULL;
+ if (!match_word(&pos, "when")) return NULL;
ast_t *subject = optional(ctx, &pos, parse_declaration);
- if (!subject) subject = expect(ctx, start, &pos, parse_expr,
- "I expected to find an expression for this 'when'");
+ if (!subject) subject = expect(ctx, start, &pos, parse_expr, "I expected to find an expression for this 'when'");
when_clause_t *clauses = NULL;
const char *tmp = pos;
@@ -1023,14 +984,14 @@ PARSER(parse_when) {
spaces(&pos);
ast_t *pattern = expect(ctx, start, &pos, parse_expr, "I expected a pattern to match here");
spaces(&pos);
- when_clause_t *new_clauses = new(when_clause_t, .pattern=pattern, .next=clauses);
+ when_clause_t *new_clauses = new (when_clause_t, .pattern = pattern, .next = clauses);
while (match(&pos, ",")) {
pattern = expect(ctx, start, &pos, parse_expr, "I expected a pattern to match here");
- new_clauses = new(when_clause_t, .pattern=pattern, .next=new_clauses);
+ new_clauses = new (when_clause_t, .pattern = pattern, .next = new_clauses);
spaces(&pos);
}
(void)match_word(&pos, "then"); // Optional 'then'
- ast_t *body = expect(ctx, start, &pos, parse_block, "I expected a body for this 'when' clause");
+ ast_t *body = expect(ctx, start, &pos, parse_block, "I expected a body for this 'when' clause");
for (when_clause_t *c = new_clauses; c && c != clauses; c = c->next) {
c->body = body;
}
@@ -1044,9 +1005,9 @@ PARSER(parse_when) {
const char *else_start = pos;
if (get_indent(ctx, tmp) == starting_indent && match_word(&tmp, "else")) {
pos = tmp;
- else_body = expect(ctx, else_start, &pos, parse_block, "I expected a body for this 'else'");
+ else_body = expect(ctx, else_start, &pos, parse_block, "I expected a body for this 'else'");
}
- return NewAST(ctx->file, start, pos, When, .subject=subject, .clauses=clauses, .else_body=else_body);
+ return NewAST(ctx->file, start, pos, When, .subject = subject, .clauses = clauses, .else_body = else_body);
}
PARSER(parse_for) {
@@ -1058,12 +1019,10 @@ PARSER(parse_for) {
ast_list_t *vars = NULL;
for (;;) {
ast_t *var = optional(ctx, &pos, parse_var);
- if (var)
- vars = new(ast_list_t, .ast=var, .next=vars);
+ if (var) vars = new (ast_list_t, .ast = var, .next = vars);
spaces(&pos);
- if (!match(&pos, ","))
- break;
+ if (!match(&pos, ",")) break;
}
spaces(&pos);
@@ -1073,7 +1032,7 @@ PARSER(parse_for) {
(void)match_word(&pos, "do"); // Optional 'do'
- ast_t *body = expect(ctx, start, &pos, parse_block, "I expected a body for this 'for'");
+ ast_t *body = expect(ctx, start, &pos, parse_block, "I expected a body for this 'for'");
const char *else_start = pos;
whitespace(&else_start);
@@ -1083,15 +1042,15 @@ PARSER(parse_for) {
empty = expect(ctx, pos, &pos, parse_block, "I expected a body for this 'else'");
}
REVERSE_LIST(vars);
- return NewAST(ctx->file, start, pos, For, .vars=vars, .iter=iter, .body=body, .empty=empty);
+ return NewAST(ctx->file, start, pos, For, .vars = vars, .iter = iter, .body = body, .empty = empty);
}
PARSER(parse_do) {
// do [<indent>] body
const char *start = pos;
if (!match_word(&pos, "do")) return NULL;
- ast_t *body = expect(ctx, start, &pos, parse_block, "I expected a body for this 'do'");
- return NewAST(ctx->file, start, pos, Block, .statements=Match(body, Block)->statements);
+ ast_t *body = expect(ctx, start, &pos, parse_block, "I expected a body for this 'do'");
+ return NewAST(ctx->file, start, pos, Block, .statements = Match(body, Block)->statements);
}
PARSER(parse_while) {
@@ -1104,22 +1063,22 @@ PARSER(parse_while) {
if (match_word(&tmp, "when")) {
ast_t *when = expect(ctx, start, &pos, parse_when, "I expected a 'when' block after this");
if (!when->__data.When.else_body) when->__data.When.else_body = NewAST(ctx->file, pos, pos, Stop);
- return NewAST(ctx->file, start, pos, While, .body=when);
+ return NewAST(ctx->file, start, pos, While, .body = when);
}
(void)match_word(&pos, "do"); // Optional 'do'
ast_t *condition = expect(ctx, start, &pos, parse_expr, "I don't see a viable condition for this 'while'");
- ast_t *body = expect(ctx, start, &pos, parse_block, "I expected a body for this 'while'");
- return NewAST(ctx->file, start, pos, While, .condition=condition, .body=body);
+ ast_t *body = expect(ctx, start, &pos, parse_block, "I expected a body for this 'while'");
+ return NewAST(ctx->file, start, pos, While, .condition = condition, .body = body);
}
PARSER(parse_repeat) {
// repeat [<indent>] body
const char *start = pos;
if (!match_word(&pos, "repeat")) return NULL;
- ast_t *body = expect(ctx, start, &pos, parse_block, "I expected a body for this 'repeat'");
- return NewAST(ctx->file, start, pos, Repeat, .body=body);
+ ast_t *body = expect(ctx, start, &pos, parse_block, "I expected a body for this 'repeat'");
+ return NewAST(ctx->file, start, pos, Repeat, .body = body);
}
PARSER(parse_heap_alloc) {
@@ -1130,16 +1089,14 @@ PARSER(parse_heap_alloc) {
for (;;) {
ast_t *new_term;
- if ((new_term=parse_index_suffix(ctx, val))
- || (new_term=parse_fncall_suffix(ctx, val))
- || (new_term=parse_method_call_suffix(ctx, val))
- || (new_term=parse_field_suffix(ctx, val))) {
+ if ((new_term = parse_index_suffix(ctx, val)) || (new_term = parse_fncall_suffix(ctx, val))
+ || (new_term = parse_method_call_suffix(ctx, val)) || (new_term = parse_field_suffix(ctx, val))) {
val = new_term;
} else break;
}
pos = val->end;
- ast_t *ast = NewAST(ctx->file, start, pos, HeapAllocate, .value=val);
+ ast_t *ast = NewAST(ctx->file, start, pos, HeapAllocate, .value = val);
for (;;) {
ast_t *next = parse_optional_suffix(ctx, ast);
if (!next) next = parse_non_optional_suffix(ctx, ast);
@@ -1157,16 +1114,14 @@ PARSER(parse_stack_reference) {
for (;;) {
ast_t *new_term;
- if ((new_term=parse_index_suffix(ctx, val))
- || (new_term=parse_fncall_suffix(ctx, val))
- || (new_term=parse_method_call_suffix(ctx, val))
- || (new_term=parse_field_suffix(ctx, val))) {
+ if ((new_term = parse_index_suffix(ctx, val)) || (new_term = parse_fncall_suffix(ctx, val))
+ || (new_term = parse_method_call_suffix(ctx, val)) || (new_term = parse_field_suffix(ctx, val))) {
val = new_term;
} else break;
}
pos = val->end;
- ast_t *ast = NewAST(ctx->file, start, pos, StackReference, .value=val);
+ ast_t *ast = NewAST(ctx->file, start, pos, StackReference, .value = val);
for (;;) {
ast_t *next = parse_optional_suffix(ctx, ast);
if (!next) next = parse_non_optional_suffix(ctx, ast);
@@ -1181,7 +1136,7 @@ PARSER(parse_not) {
if (!match_word(&pos, "not")) return NULL;
spaces(&pos);
ast_t *val = expect(ctx, start, &pos, parse_term, "I expected an expression for this 'not'");
- return NewAST(ctx->file, start, pos, Not, .value=val);
+ return NewAST(ctx->file, start, pos, Not, .value = val);
}
PARSER(parse_negative) {
@@ -1189,21 +1144,18 @@ PARSER(parse_negative) {
if (!match(&pos, "-")) return NULL;
spaces(&pos);
ast_t *val = expect(ctx, start, &pos, parse_term, "I expected an expression for this '-'");
- return NewAST(ctx->file, start, pos, Negative, .value=val);
+ return NewAST(ctx->file, start, pos, Negative, .value = val);
}
PARSER(parse_bool) {
const char *start = pos;
- if (match_word(&pos, "yes"))
- return NewAST(ctx->file, start, pos, Bool, .b=true);
- else if (match_word(&pos, "no"))
- return NewAST(ctx->file, start, pos, Bool, .b=false);
- else
- return NULL;
+ if (match_word(&pos, "yes")) return NewAST(ctx->file, start, pos, Bool, .b = true);
+ else if (match_word(&pos, "no")) return NewAST(ctx->file, start, pos, Bool, .b = false);
+ else return NULL;
}
-ast_list_t *_parse_text_helper(parse_ctx_t *ctx, const char **out_pos, char open_quote, char close_quote, char open_interp, bool allow_escapes)
-{
+ast_list_t *_parse_text_helper(parse_ctx_t *ctx, const char **out_pos, char open_quote, char close_quote,
+ char open_interp, bool allow_escapes) {
const char *pos = *out_pos;
int64_t starting_indent = get_indent(ctx, pos);
int64_t string_indent = starting_indent + SPACES_PER_INDENT;
@@ -1213,27 +1165,29 @@ ast_list_t *_parse_text_helper(parse_ctx_t *ctx, const char **out_pos, char open
int depth = 1;
bool leading_newline = false;
int64_t plain_span_len = 0;
-#define FLUSH_PLAIN_SPAN() do { \
- if (plain_span_len > 0) { \
- chunk = Texts(chunk, Text$from_strn(pos - plain_span_len, (size_t)plain_span_len)); \
- plain_span_len = 0; \
- } } while (0)
- for (const char *end = ctx->file->text + ctx->file->len; pos < end && depth > 0; ) {
+#define FLUSH_PLAIN_SPAN() \
+ do { \
+ if (plain_span_len > 0) { \
+ chunk = Texts(chunk, Text$from_strn(pos - plain_span_len, (size_t)plain_span_len)); \
+ plain_span_len = 0; \
+ } \
+ } while (0)
+ for (const char *end = ctx->file->text + ctx->file->len; pos < end && depth > 0;) {
const char *after_indentation = pos;
if (*pos == open_interp) { // Interpolation
FLUSH_PLAIN_SPAN();
const char *interp_start = pos;
if (chunk.length > 0) {
- ast_t *literal = NewAST(ctx->file, chunk_start, pos, TextLiteral, .text=chunk);
- chunks = new(ast_list_t, .ast=literal, .next=chunks);
+ ast_t *literal = NewAST(ctx->file, chunk_start, pos, TextLiteral, .text = chunk);
+ chunks = new (ast_list_t, .ast = literal, .next = chunks);
chunk = EMPTY_TEXT;
}
++pos;
ast_t *interp;
if (*pos == ' ' || *pos == '\t')
- parser_err(ctx, pos, pos+1, "Whitespace is not allowed before an interpolation here");
+ parser_err(ctx, pos, pos + 1, "Whitespace is not allowed before an interpolation here");
interp = expect(ctx, interp_start, &pos, parse_term_no_suffix, "I expected an interpolation term here");
- chunks = new(ast_list_t, .ast=interp, .next=chunks);
+ chunks = new (ast_list_t, .ast = interp, .next = chunks);
chunk_start = pos;
} else if (allow_escapes && *pos == '\\') {
FLUSH_PLAIN_SPAN();
@@ -1248,8 +1202,7 @@ ast_list_t *_parse_text_helper(parse_ctx_t *ctx, const char **out_pos, char open
} else if (!leading_newline && *pos == close_quote) { // Nested pair end
if (get_indent(ctx, pos) == starting_indent) {
--depth;
- if (depth == 0)
- break;
+ if (depth == 0) break;
}
plain_span_len += 1;
++pos;
@@ -1270,14 +1223,14 @@ ast_list_t *_parse_text_helper(parse_ctx_t *ctx, const char **out_pos, char open
// Multi-line split
continue;
} else {
- parser_err(ctx, pos, eol(pos), "This multi-line string should be either indented or have '..' at the front");
+ parser_err(ctx, pos, eol(pos),
+ "This multi-line string should be either indented or have '..' at the front");
}
} else { // Plain character
ucs4_t codepoint;
- const char *next = (const char*)u8_next(&codepoint, (const uint8_t*)pos);
+ const char *next = (const char *)u8_next(&codepoint, (const uint8_t *)pos);
plain_span_len += (int64_t)(next - pos);
- if (next == NULL)
- break;
+ if (next == NULL) break;
pos = next;
}
}
@@ -1286,8 +1239,8 @@ ast_list_t *_parse_text_helper(parse_ctx_t *ctx, const char **out_pos, char open
#undef FLUSH_PLAIN_SPAN
if (chunk.length > 0) {
- ast_t *literal = NewAST(ctx->file, chunk_start, pos, TextLiteral, .text=chunk);
- chunks = new(ast_list_t, .ast=literal, .next=chunks);
+ ast_t *literal = NewAST(ctx->file, chunk_start, pos, TextLiteral, .text = chunk);
+ chunks = new (ast_list_t, .ast = literal, .next = chunks);
chunk = EMPTY_TEXT;
}
@@ -1323,7 +1276,8 @@ PARSER(parse_text) {
}
static const char *quote_chars = "\"'`|/;([{<";
if (!strchr(quote_chars, *pos))
- parser_err(ctx, pos, pos+1, "This is not a valid string quotation character. Valid characters are: \"'`|/;([{<");
+ parser_err(ctx, pos, pos + 1,
+ "This is not a valid string quotation character. Valid characters are: \"'`|/;([{<");
open_quote = *pos;
++pos;
close_quote = closing[(int)open_quote] ? closing[(int)open_quote] : open_quote;
@@ -1334,18 +1288,16 @@ PARSER(parse_text) {
bool allow_escapes = (open_quote != '`');
ast_list_t *chunks = _parse_text_helper(ctx, &pos, open_quote, close_quote, open_interp, allow_escapes);
bool colorize = match(&pos, "~") && match_word(&pos, "colorized");
- return NewAST(ctx->file, start, pos, TextJoin, .lang=lang, .children=chunks, .colorize=colorize);
+ return NewAST(ctx->file, start, pos, TextJoin, .lang = lang, .children = chunks, .colorize = colorize);
}
PARSER(parse_path) {
// "(" ("~/" / "./" / "../" / "/") ... ")"
const char *start = pos;
- if (!match(&pos, "("))
- return NULL;
+ if (!match(&pos, "(")) return NULL;
- if (!(*pos == '~' || *pos == '.' || *pos == '/'))
- return NULL;
+ if (!(*pos == '~' || *pos == '.' || *pos == '/')) return NULL;
const char *path_start = pos;
size_t len = 1;
@@ -1360,13 +1312,13 @@ PARSER(parse_path) {
paren_depth -= 1;
if (paren_depth <= 0) break;
} else if (pos[len] == '\r' || pos[len] == '\n') {
- parser_err(ctx, path_start, &pos[len-1], "This path was not closed");
+ parser_err(ctx, path_start, &pos[len - 1], "This path was not closed");
}
len += 1;
}
pos += len + 1;
- char *path = String(string_slice(path_start, .length=len));
- for (char *src = path, *dest = path; ; ) {
+ char *path = String(string_slice(path_start, .length = len));
+ for (char *src = path, *dest = path;;) {
if (src[0] == '\\') {
*(dest++) = src[1];
src += 2;
@@ -1377,7 +1329,7 @@ PARSER(parse_path) {
break;
}
}
- return NewAST(ctx->file, start, pos, Path, .path=path);
+ return NewAST(ctx->file, start, pos, Path, .path = path);
}
PARSER(parse_pass) {
@@ -1389,7 +1341,7 @@ PARSER(parse_defer) {
const char *start = pos;
if (!match_word(&pos, "defer")) return NULL;
ast_t *body = expect(ctx, start, &pos, parse_block, "I expected a block to be deferred here");
- return NewAST(ctx->file, start, pos, Defer, .body=body);
+ return NewAST(ctx->file, start, pos, Defer, .body = body);
}
PARSER(parse_skip) {
@@ -1399,7 +1351,7 @@ PARSER(parse_skip) {
if (match_word(&pos, "for")) target = "for";
else if (match_word(&pos, "while")) target = "while";
else target = get_id(&pos);
- ast_t *skip = NewAST(ctx->file, start, pos, Skip, .target=target);
+ ast_t *skip = NewAST(ctx->file, start, pos, Skip, .target = target);
skip = parse_optional_conditional_suffix(ctx, skip);
return skip;
}
@@ -1411,7 +1363,7 @@ PARSER(parse_stop) {
if (match_word(&pos, "for")) target = "for";
else if (match_word(&pos, "while")) target = "while";
else target = get_id(&pos);
- ast_t *stop = NewAST(ctx->file, start, pos, Stop, .target=target);
+ ast_t *stop = NewAST(ctx->file, start, pos, Stop, .target = target);
stop = parse_optional_conditional_suffix(ctx, stop);
return stop;
}
@@ -1420,112 +1372,87 @@ PARSER(parse_return) {
const char *start = pos;
if (!match_word(&pos, "return")) return NULL;
ast_t *value = optional(ctx, &pos, parse_expr);
- ast_t *ret = NewAST(ctx->file, start, pos, Return, .value=value);
+ ast_t *ret = NewAST(ctx->file, start, pos, Return, .value = value);
ret = parse_optional_conditional_suffix(ctx, ret);
return ret;
}
PARSER(parse_lambda) {
const char *start = pos;
- if (!match_word(&pos, "func"))
- return NULL;
+ if (!match_word(&pos, "func")) return NULL;
spaces(&pos);
- if (!match(&pos, "("))
- return NULL;
+ if (!match(&pos, "(")) return NULL;
arg_ast_t *args = parse_args(ctx, &pos);
spaces(&pos);
type_ast_t *ret = match(&pos, "->") ? optional(ctx, &pos, parse_type) : NULL;
spaces(&pos);
expect_closing(ctx, &pos, ")", "I was expecting a ')' to finish this anonymous function's arguments");
ast_t *body = optional(ctx, &pos, parse_block);
- if (!body) body = NewAST(ctx->file, pos, pos, Block, .statements=NULL);
- return NewAST(ctx->file, start, pos, Lambda, .id=ctx->next_lambda_id++, .args=args, .ret_type=ret, .body=body);
+ if (!body) body = NewAST(ctx->file, pos, pos, Block, .statements = NULL);
+ return NewAST(ctx->file, start, pos, Lambda, .id = ctx->next_lambda_id++, .args = args, .ret_type = ret,
+ .body = body);
}
PARSER(parse_none) {
const char *start = pos;
- if (!match_word(&pos, "none"))
- return NULL;
+ if (!match_word(&pos, "none")) return NULL;
return NewAST(ctx->file, start, pos, None);
}
PARSER(parse_deserialize) {
const char *start = pos;
- if (!match_word(&pos, "deserialize"))
- return NULL;
+ if (!match_word(&pos, "deserialize")) return NULL;
spaces(&pos);
expect_str(ctx, start, &pos, "(", "I expected arguments for this `deserialize` call");
whitespace(&pos);
ast_t *value = expect(ctx, start, &pos, parse_extended_expr, "I expected an expression here");
whitespace(&pos);
- expect_str(ctx, start, &pos, "->", "I expected a `-> Type` for this `deserialize` call so I know what it deserializes to");
+ expect_str(ctx, start, &pos, "->",
+ "I expected a `-> Type` for this `deserialize` call so I know what it deserializes to");
whitespace(&pos);
type_ast_t *type = expect(ctx, start, &pos, parse_type, "I couldn't parse the type for this deserialization");
whitespace(&pos);
expect_closing(ctx, &pos, ")", "I expected a closing ')' for this `deserialize` call");
- return NewAST(ctx->file, start, pos, Deserialize, .value=value, .type=type);
+ return NewAST(ctx->file, start, pos, Deserialize, .value = value, .type = type);
}
PARSER(parse_var) {
const char *start = pos;
- const char* name = get_id(&pos);
+ const char *name = get_id(&pos);
if (!name) return NULL;
- return NewAST(ctx->file, start, pos, Var, .name=name);
+ return NewAST(ctx->file, start, pos, Var, .name = name);
}
PARSER(parse_term_no_suffix) {
spaces(&pos);
ast_t *term = NULL;
- (void)(
- false
- || (term=parse_none(ctx, pos))
- || (term=parse_num(ctx, pos)) // Must come before int
- || (term=parse_int(ctx, pos))
- || (term=parse_negative(ctx, pos)) // Must come after num/int
- || (term=parse_heap_alloc(ctx, pos))
- || (term=parse_stack_reference(ctx, pos))
- || (term=parse_bool(ctx, pos))
- || (term=parse_text(ctx, pos))
- || (term=parse_path(ctx, pos))
- || (term=parse_lambda(ctx, pos))
- || (term=parse_parens(ctx, pos))
- || (term=parse_table(ctx, pos))
- || (term=parse_set(ctx, pos))
- || (term=parse_deserialize(ctx, pos))
- || (term=parse_var(ctx, pos))
- || (term=parse_list(ctx, pos))
- || (term=parse_reduction(ctx, pos))
- || (term=parse_pass(ctx, pos))
- || (term=parse_defer(ctx, pos))
- || (term=parse_skip(ctx, pos))
- || (term=parse_stop(ctx, pos))
- || (term=parse_return(ctx, pos))
- || (term=parse_not(ctx, pos))
- || (term=parse_extern(ctx, pos))
- || (term=parse_inline_c(ctx, pos))
- );
+ (void)(false || (term = parse_none(ctx, pos)) || (term = parse_num(ctx, pos)) // Must come before int
+ || (term = parse_int(ctx, pos)) || (term = parse_negative(ctx, pos)) // Must come after num/int
+ || (term = parse_heap_alloc(ctx, pos)) || (term = parse_stack_reference(ctx, pos))
+ || (term = parse_bool(ctx, pos)) || (term = parse_text(ctx, pos)) || (term = parse_path(ctx, pos))
+ || (term = parse_lambda(ctx, pos)) || (term = parse_parens(ctx, pos)) || (term = parse_table(ctx, pos))
+ || (term = parse_set(ctx, pos)) || (term = parse_deserialize(ctx, pos)) || (term = parse_var(ctx, pos))
+ || (term = parse_list(ctx, pos)) || (term = parse_reduction(ctx, pos)) || (term = parse_pass(ctx, pos))
+ || (term = parse_defer(ctx, pos)) || (term = parse_skip(ctx, pos)) || (term = parse_stop(ctx, pos))
+ || (term = parse_return(ctx, pos)) || (term = parse_not(ctx, pos)) || (term = parse_extern(ctx, pos))
+ || (term = parse_inline_c(ctx, pos)));
return term;
}
PARSER(parse_term) {
const char *start = pos;
- if (match(&pos, "???"))
- parser_err(ctx, start, pos, "This value needs to be filled in!");
+ if (match(&pos, "???")) parser_err(ctx, start, pos, "This value needs to be filled in!");
ast_t *term = parse_term_no_suffix(ctx, pos);
if (!term) return NULL;
- for (bool progress = true; progress; ) {
+ for (bool progress = true; progress;) {
ast_t *new_term;
- progress = (false
- || (new_term=parse_index_suffix(ctx, term))
- || (new_term=parse_method_call_suffix(ctx, term))
- || (new_term=parse_field_suffix(ctx, term))
- || (new_term=parse_fncall_suffix(ctx, term))
- || (new_term=parse_optional_suffix(ctx, term))
- || (new_term=parse_non_optional_suffix(ctx, term))
- );
+ progress =
+ (false || (new_term = parse_index_suffix(ctx, term)) || (new_term = parse_method_call_suffix(ctx, term))
+ || (new_term = parse_field_suffix(ctx, term)) || (new_term = parse_fncall_suffix(ctx, term))
+ || (new_term = parse_optional_suffix(ctx, term)) || (new_term = parse_non_optional_suffix(ctx, term)));
if (progress) term = new_term;
}
return term;
@@ -1560,18 +1487,16 @@ ast_t *parse_method_call_suffix(parse_ctx_t *ctx, ast_t *self) {
if (name) parser_err(ctx, arg_start, pos, "I expected an argument here");
break;
}
- args = new(arg_ast_t, .name=name, .value=arg, .next=args);
- if (!match_separator(&pos))
- break;
+ args = new (arg_ast_t, .name = name, .value = arg, .next = args);
+ if (!match_separator(&pos)) break;
}
REVERSE_LIST(args);
whitespace(&pos);
- if (!match(&pos, ")"))
- parser_err(ctx, start, pos, "This parenthesis is unclosed");
+ if (!match(&pos, ")")) parser_err(ctx, start, pos, "This parenthesis is unclosed");
- return NewAST(ctx->file, start, pos, MethodCall, .self=self, .name=fn, .args=args);
+ return NewAST(ctx->file, start, pos, MethodCall, .self = self, .name = fn, .args = args);
}
ast_t *parse_fncall_suffix(parse_ctx_t *ctx, ast_t *fn) {
@@ -1596,26 +1521,22 @@ ast_t *parse_fncall_suffix(parse_ctx_t *ctx, ast_t *fn) {
ast_t *arg = optional(ctx, &pos, parse_expr);
if (!arg) {
- if (name)
- parser_err(ctx, arg_start, pos, "I expected an argument here");
+ if (name) parser_err(ctx, arg_start, pos, "I expected an argument here");
break;
}
- args = new(arg_ast_t, .name=name, .value=arg, .next=args);
- if (!match_separator(&pos))
- break;
+ args = new (arg_ast_t, .name = name, .value = arg, .next = args);
+ if (!match_separator(&pos)) break;
}
whitespace(&pos);
- if (!match(&pos, ")"))
- parser_err(ctx, start, pos, "This parenthesis is unclosed");
+ if (!match(&pos, ")")) parser_err(ctx, start, pos, "This parenthesis is unclosed");
REVERSE_LIST(args);
- return NewAST(ctx->file, start, pos, FunctionCall, .fn=fn, .args=args);
+ return NewAST(ctx->file, start, pos, FunctionCall, .fn = fn, .args = args);
}
-ast_e match_binary_operator(const char **pos)
-{
+ast_e match_binary_operator(const char **pos) {
switch (**pos) {
case '+': {
*pos += 1;
@@ -1633,20 +1554,18 @@ ast_e match_binary_operator(const char **pos)
case '<': {
*pos += 1;
if (match(pos, "=")) return LessThanOrEquals; // "<="
- else if (match(pos, ">")) return Compare; // "<>"
+ else if (match(pos, ">")) return Compare; // "<>"
else if (match(pos, "<")) {
- if (match(pos, "<"))
- return UnsignedLeftShift; // "<<<"
- return LeftShift; // "<<"
+ if (match(pos, "<")) return UnsignedLeftShift; // "<<<"
+ return LeftShift; // "<<"
} else return LessThan;
}
case '>': {
*pos += 1;
if (match(pos, "=")) return GreaterThanOrEquals; // ">="
if (match(pos, ">")) {
- if (match(pos, ">"))
- return UnsignedRightShift; // ">>>"
- return RightShift; // ">>"
+ if (match(pos, ">")) return UnsignedRightShift; // ">>>"
+ return RightShift; // ">>"
}
return GreaterThan;
}
@@ -1672,20 +1591,17 @@ static ast_t *parse_infix_expr(parse_ctx_t *ctx, const char *pos, int min_tightn
int64_t starting_line = get_line_number(ctx->file, pos);
int64_t starting_indent = get_indent(ctx, pos);
spaces(&pos);
- for (ast_e op; (op=match_binary_operator(&pos)) != Unknown && op_tightness[op] >= min_tightness; spaces(&pos)) {
+ for (ast_e op; (op = match_binary_operator(&pos)) != Unknown && op_tightness[op] >= min_tightness; spaces(&pos)) {
ast_t *key = NULL;
if (op == Min || op == Max) {
- key = NewAST(ctx->file, pos, pos, Var, .name="$");
- for (bool progress = true; progress; ) {
+ key = NewAST(ctx->file, pos, pos, Var, .name = "$");
+ for (bool progress = true; progress;) {
ast_t *new_term;
- progress = (false
- || (new_term=parse_index_suffix(ctx, key))
- || (new_term=parse_method_call_suffix(ctx, key))
- || (new_term=parse_field_suffix(ctx, key))
- || (new_term=parse_fncall_suffix(ctx, key))
- || (new_term=parse_optional_suffix(ctx, key))
- || (new_term=parse_non_optional_suffix(ctx, key))
- );
+ progress =
+ (false || (new_term = parse_index_suffix(ctx, key))
+ || (new_term = parse_method_call_suffix(ctx, key)) || (new_term = parse_field_suffix(ctx, key))
+ || (new_term = parse_fncall_suffix(ctx, key)) || (new_term = parse_optional_suffix(ctx, key))
+ || (new_term = parse_non_optional_suffix(ctx, key)));
if (progress) key = new_term;
}
if (key && key->tag == Var) key = NULL;
@@ -1699,21 +1615,20 @@ static ast_t *parse_infix_expr(parse_ctx_t *ctx, const char *pos, int min_tightn
ast_t *rhs = parse_infix_expr(ctx, pos, op_tightness[op] + 1);
if (!rhs) break;
pos = rhs->end;
-
+
if (op == Min) {
- return NewAST(ctx->file, lhs->start, rhs->end, Min, .lhs=lhs, .rhs=rhs, .key=key);
+ return NewAST(ctx->file, lhs->start, rhs->end, Min, .lhs = lhs, .rhs = rhs, .key = key);
} else if (op == Max) {
- return NewAST(ctx->file, lhs->start, rhs->end, Max, .lhs=lhs, .rhs=rhs, .key=key);
+ return NewAST(ctx->file, lhs->start, rhs->end, Max, .lhs = lhs, .rhs = rhs, .key = key);
} else {
- lhs = new(ast_t, .file=ctx->file, .start=lhs->start, .end=rhs->end, .tag=op, .__data.Plus.lhs=lhs, .__data.Plus.rhs=rhs);
+ lhs = new (ast_t, .file = ctx->file, .start = lhs->start, .end = rhs->end, .tag = op,
+ .__data.Plus.lhs = lhs, .__data.Plus.rhs = rhs);
}
}
return lhs;
}
-PARSER(parse_expr) {
- return parse_infix_expr(ctx, pos, 0);
-}
+PARSER(parse_expr) { return parse_infix_expr(ctx, pos, 0); }
PARSER(parse_declaration) {
const char *start = pos;
@@ -1731,17 +1646,15 @@ PARSER(parse_declaration) {
if (!val) {
if (optional(ctx, &pos, parse_use))
parser_err(ctx, start, pos, "'use' statements are only allowed at the top level of a file");
- else
- parser_err(ctx, pos, eol(pos), "This is not a valid expression");
+ else parser_err(ctx, pos, eol(pos), "This is not a valid expression");
}
}
- return NewAST(ctx->file, start, pos, Declare, .var=var, .type=type, .value=val);
+ return NewAST(ctx->file, start, pos, Declare, .var = var, .type = type, .value = val);
}
PARSER(parse_top_declaration) {
ast_t *declaration = parse_declaration(ctx, pos);
- if (declaration)
- declaration->__data.Declare.top_level = true;
+ if (declaration) declaration->__data.Declare.top_level = true;
return declaration;
}
@@ -1766,7 +1679,8 @@ PARSER(parse_update) {
else if (match(&pos, "xor=")) op = XorUpdate;
else return NULL;
ast_t *rhs = expect(ctx, start, &pos, parse_extended_expr, "I expected an expression here");
- return new(ast_t, .file=ctx->file, .start=start, .end=pos, .tag=op, .__data.PlusUpdate.lhs=lhs, .__data.PlusUpdate.rhs=rhs);
+ return new (ast_t, .file = ctx->file, .start = start, .end = pos, .tag = op, .__data.PlusUpdate.lhs = lhs,
+ .__data.PlusUpdate.rhs = rhs);
}
PARSER(parse_assignment) {
@@ -1775,7 +1689,7 @@ PARSER(parse_assignment) {
for (;;) {
ast_t *lhs = optional(ctx, &pos, parse_term);
if (!lhs) break;
- targets = new(ast_list_t, .ast=lhs, .next=targets);
+ targets = new (ast_list_t, .ast = lhs, .next = targets);
spaces(&pos);
if (!match(&pos, ",")) break;
whitespace(&pos);
@@ -1791,7 +1705,7 @@ PARSER(parse_assignment) {
for (;;) {
ast_t *rhs = optional(ctx, &pos, parse_extended_expr);
if (!rhs) break;
- values = new(ast_list_t, .ast=rhs, .next=values);
+ values = new (ast_list_t, .ast = rhs, .next = values);
spaces(&pos);
if (!match(&pos, ",")) break;
whitespace(&pos);
@@ -1800,30 +1714,23 @@ PARSER(parse_assignment) {
REVERSE_LIST(targets);
REVERSE_LIST(values);
- return NewAST(ctx->file, start, pos, Assign, .targets=targets, .values=values);
+ return NewAST(ctx->file, start, pos, Assign, .targets = targets, .values = values);
}
PARSER(parse_statement) {
ast_t *stmt = NULL;
- if ((stmt=parse_declaration(ctx, pos))
- || (stmt=parse_doctest(ctx, pos))
- || (stmt=parse_assert(ctx, pos)))
+ if ((stmt = parse_declaration(ctx, pos)) || (stmt = parse_doctest(ctx, pos)) || (stmt = parse_assert(ctx, pos)))
return stmt;
- if (!(false
- || (stmt=parse_update(ctx, pos))
- || (stmt=parse_assignment(ctx, pos))
- ))
+ if (!(false || (stmt = parse_update(ctx, pos)) || (stmt = parse_assignment(ctx, pos))))
stmt = parse_extended_expr(ctx, pos);
-
- for (bool progress = (stmt != NULL); progress; ) {
+
+ for (bool progress = (stmt != NULL); progress;) {
ast_t *new_stmt;
progress = false;
if (stmt->tag == Var) {
- progress = (false
- || (new_stmt=parse_method_call_suffix(ctx, stmt))
- || (new_stmt=parse_fncall_suffix(ctx, stmt))
- );
+ progress = (false || (new_stmt = parse_method_call_suffix(ctx, stmt))
+ || (new_stmt = parse_fncall_suffix(ctx, stmt)));
} else if (stmt->tag == FunctionCall) {
new_stmt = parse_optional_conditional_suffix(ctx, stmt);
progress = (new_stmt != stmt);
@@ -1832,20 +1739,14 @@ PARSER(parse_statement) {
if (progress) stmt = new_stmt;
}
return stmt;
-
}
PARSER(parse_extended_expr) {
ast_t *expr = NULL;
- if (false
- || (expr=optional(ctx, &pos, parse_for))
- || (expr=optional(ctx, &pos, parse_while))
- || (expr=optional(ctx, &pos, parse_if))
- || (expr=optional(ctx, &pos, parse_when))
- || (expr=optional(ctx, &pos, parse_repeat))
- || (expr=optional(ctx, &pos, parse_do))
- )
+ if (false || (expr = optional(ctx, &pos, parse_for)) || (expr = optional(ctx, &pos, parse_while))
+ || (expr = optional(ctx, &pos, parse_if)) || (expr = optional(ctx, &pos, parse_when))
+ || (expr = optional(ctx, &pos, parse_repeat)) || (expr = optional(ctx, &pos, parse_do)))
return expr;
return parse_expr(ctx, pos);
@@ -1863,7 +1764,7 @@ PARSER(parse_block) {
spaces(&pos);
ast_t *stmt = optional(ctx, &pos, parse_statement);
if (!stmt) break;
- statements = new(ast_list_t, .ast=stmt, .next=statements);
+ statements = new (ast_list_t, .ast = stmt, .next = statements);
spaces(&pos);
if (!match(&pos, ";")) break;
}
@@ -1872,7 +1773,7 @@ PARSER(parse_block) {
}
if (indent(ctx, &pos)) {
- indented:;
+ indented:;
int64_t block_indent = get_indent(ctx, pos);
whitespace(&pos);
while (*pos) {
@@ -1889,17 +1790,15 @@ PARSER(parse_block) {
parser_err(ctx, line_start, eol(pos), "'use' statements are only allowed at the top level");
spaces(&pos);
- if (*pos && *pos != '\r' && *pos != '\n')
- parser_err(ctx, pos, eol(pos), "I couldn't parse this line");
+ if (*pos && *pos != '\r' && *pos != '\n') parser_err(ctx, pos, eol(pos), "I couldn't parse this line");
break;
}
- statements = new(ast_list_t, .ast=stmt, .next=statements);
+ statements = new (ast_list_t, .ast = stmt, .next = statements);
whitespace(&pos);
// Guard against having two valid statements on the same line, separated by spaces (but no newlines):
if (!memchr(stmt->end, '\n', (size_t)(pos - stmt->end))) {
- if (*pos)
- parser_err(ctx, pos, eol(pos), "I don't know how to parse the rest of this line");
+ if (*pos) parser_err(ctx, pos, eol(pos), "I don't know how to parse the rest of this line");
pos = stmt->end;
break;
}
@@ -1911,7 +1810,7 @@ PARSER(parse_block) {
}
}
REVERSE_LIST(statements);
- return NewAST(ctx->file, start, pos, Block, .statements=statements);
+ return NewAST(ctx->file, start, pos, Block, .statements = statements);
}
PARSER(parse_namespace) {
@@ -1924,18 +1823,12 @@ PARSER(parse_namespace) {
whitespace(&next);
if (get_indent(ctx, next) != indent) break;
ast_t *stmt;
- if ((stmt=optional(ctx, &pos, parse_struct_def))
- ||(stmt=optional(ctx, &pos, parse_func_def))
- ||(stmt=optional(ctx, &pos, parse_enum_def))
- ||(stmt=optional(ctx, &pos, parse_lang_def))
- ||(stmt=optional(ctx, &pos, parse_extend))
- ||(stmt=optional(ctx, &pos, parse_convert_def))
- ||(stmt=optional(ctx, &pos, parse_use))
- ||(stmt=optional(ctx, &pos, parse_extern))
- ||(stmt=optional(ctx, &pos, parse_inline_c))
- ||(stmt=optional(ctx, &pos, parse_declaration)))
- {
- statements = new(ast_list_t, .ast=stmt, .next=statements);
+ if ((stmt = optional(ctx, &pos, parse_struct_def)) || (stmt = optional(ctx, &pos, parse_func_def))
+ || (stmt = optional(ctx, &pos, parse_enum_def)) || (stmt = optional(ctx, &pos, parse_lang_def))
+ || (stmt = optional(ctx, &pos, parse_extend)) || (stmt = optional(ctx, &pos, parse_convert_def))
+ || (stmt = optional(ctx, &pos, parse_use)) || (stmt = optional(ctx, &pos, parse_extern))
+ || (stmt = optional(ctx, &pos, parse_inline_c)) || (stmt = optional(ctx, &pos, parse_declaration))) {
+ statements = new (ast_list_t, .ast = stmt, .next = statements);
pos = stmt->end;
whitespace(&pos); // TODO: check for newline
// if (!(space_types & WHITESPACE_NEWLINES)) {
@@ -1949,7 +1842,7 @@ PARSER(parse_namespace) {
}
}
REVERSE_LIST(statements);
- return NewAST(ctx->file, start, pos, Block, .statements=statements);
+ return NewAST(ctx->file, start, pos, Block, .statements = statements);
}
PARSER(parse_file_body) {
@@ -1961,18 +1854,12 @@ PARSER(parse_file_body) {
whitespace(&next);
if (get_indent(ctx, next) != 0) break;
ast_t *stmt;
- if ((stmt=optional(ctx, &pos, parse_struct_def))
- ||(stmt=optional(ctx, &pos, parse_func_def))
- ||(stmt=optional(ctx, &pos, parse_enum_def))
- ||(stmt=optional(ctx, &pos, parse_lang_def))
- ||(stmt=optional(ctx, &pos, parse_extend))
- ||(stmt=optional(ctx, &pos, parse_convert_def))
- ||(stmt=optional(ctx, &pos, parse_use))
- ||(stmt=optional(ctx, &pos, parse_extern))
- ||(stmt=optional(ctx, &pos, parse_inline_c))
- ||(stmt=optional(ctx, &pos, parse_top_declaration)))
- {
- statements = new(ast_list_t, .ast=stmt, .next=statements);
+ if ((stmt = optional(ctx, &pos, parse_struct_def)) || (stmt = optional(ctx, &pos, parse_func_def))
+ || (stmt = optional(ctx, &pos, parse_enum_def)) || (stmt = optional(ctx, &pos, parse_lang_def))
+ || (stmt = optional(ctx, &pos, parse_extend)) || (stmt = optional(ctx, &pos, parse_convert_def))
+ || (stmt = optional(ctx, &pos, parse_use)) || (stmt = optional(ctx, &pos, parse_extern))
+ || (stmt = optional(ctx, &pos, parse_inline_c)) || (stmt = optional(ctx, &pos, parse_top_declaration))) {
+ statements = new (ast_list_t, .ast = stmt, .next = statements);
pos = stmt->end;
whitespace(&pos); // TODO: check for newline
} else {
@@ -1984,7 +1871,7 @@ PARSER(parse_file_body) {
parser_err(ctx, pos, eol(pos), "I expect all top-level statements to be declarations of some kind");
}
REVERSE_LIST(statements);
- return NewAST(ctx->file, start, pos, Block, .statements=statements);
+ return NewAST(ctx->file, start, pos, Block, .statements = statements);
}
PARSER(parse_struct_def) {
@@ -1999,8 +1886,7 @@ PARSER(parse_struct_def) {
if (!name) parser_err(ctx, start, pos, "I expected a name for this struct");
spaces(&pos);
- if (!match(&pos, "("))
- parser_err(ctx, pos, pos, "I expected a '(' and a list of fields here");
+ if (!match(&pos, "(")) parser_err(ctx, pos, pos, "I expected a '(' and a list of fields here");
arg_ast_t *fields = parse_args(ctx, &pos);
@@ -2015,18 +1901,16 @@ PARSER(parse_struct_def) {
external = true;
} else if (match_word(&pos, "opaque")) {
if (fields)
- parser_err(ctx, pos-strlen("opaque"), pos, "A struct can't be opaque if it has fields defined");
+ parser_err(ctx, pos - strlen("opaque"), pos, "A struct can't be opaque if it has fields defined");
opaque = true;
} else {
break;
}
- if (!match_separator(&pos))
- break;
+ if (!match_separator(&pos)) break;
}
}
-
expect_closing(ctx, &pos, ")", "I wasn't able to parse the rest of this struct");
ast_t *namespace = NULL;
@@ -2037,10 +1921,9 @@ PARSER(parse_struct_def) {
pos = ns_pos;
namespace = optional(ctx, &pos, parse_namespace);
}
- if (!namespace)
- namespace = NewAST(ctx->file, pos, pos, Block, .statements=NULL);
- return NewAST(ctx->file, start, pos, StructDef, .name=name, .fields=fields, .namespace=namespace,
- .secret=secret, .external=external, .opaque=opaque);
+ if (!namespace) namespace = NewAST(ctx->file, pos, pos, Block, .statements = NULL);
+ return NewAST(ctx->file, start, pos, StructDef, .name = name, .fields = fields, .namespace = namespace,
+ .secret = secret, .external = external, .opaque = opaque);
}
PARSER(parse_enum_def) {
@@ -2050,8 +1933,7 @@ PARSER(parse_enum_def) {
int64_t starting_indent = get_indent(ctx, pos);
spaces(&pos);
const char *name = get_id(&pos);
- if (!name)
- parser_err(ctx, start, pos, "I expected a name for this enum");
+ if (!name) parser_err(ctx, start, pos, "I expected a name for this enum");
spaces(&pos);
if (!match(&pos, "(")) return NULL;
@@ -2079,10 +1961,9 @@ PARSER(parse_enum_def) {
fields = NULL;
}
- tags = new(tag_ast_t, .name=tag_name, .fields=fields, .secret=secret, .next=tags);
+ tags = new (tag_ast_t, .name = tag_name, .fields = fields, .secret = secret, .next = tags);
- if (!match_separator(&pos))
- break;
+ if (!match_separator(&pos)) break;
}
whitespace(&pos);
@@ -2090,8 +1971,7 @@ PARSER(parse_enum_def) {
REVERSE_LIST(tags);
- if (tags == NULL)
- parser_err(ctx, start, pos, "This enum does not have any tags!");
+ if (tags == NULL) parser_err(ctx, start, pos, "This enum does not have any tags!");
ast_t *namespace = NULL;
const char *ns_pos = pos;
@@ -2101,10 +1981,9 @@ PARSER(parse_enum_def) {
pos = ns_pos;
namespace = optional(ctx, &pos, parse_namespace);
}
- if (!namespace)
- namespace = NewAST(ctx->file, pos, pos, Block, .statements=NULL);
+ if (!namespace) namespace = NewAST(ctx->file, pos, pos, Block, .statements = NULL);
- return NewAST(ctx->file, start, pos, EnumDef, .name=name, .tags=tags, .namespace=namespace);
+ return NewAST(ctx->file, start, pos, EnumDef, .name = name, .tags = tags, .namespace = namespace);
}
PARSER(parse_lang_def) {
@@ -2114,8 +1993,7 @@ PARSER(parse_lang_def) {
int64_t starting_indent = get_indent(ctx, pos);
spaces(&pos);
const char *name = get_id(&pos);
- if (!name)
- parser_err(ctx, start, pos, "I expected a name for this lang");
+ if (!name) parser_err(ctx, start, pos, "I expected a name for this lang");
spaces(&pos);
ast_t *namespace = NULL;
@@ -2126,10 +2004,9 @@ PARSER(parse_lang_def) {
pos = ns_pos;
namespace = optional(ctx, &pos, parse_namespace);
}
- if (!namespace)
- namespace = NewAST(ctx->file, pos, pos, Block, .statements=NULL);
+ if (!namespace) namespace = NewAST(ctx->file, pos, pos, Block, .statements = NULL);
- return NewAST(ctx->file, start, pos, LangDef, .name=name, .namespace=namespace);
+ return NewAST(ctx->file, start, pos, LangDef, .name = name, .namespace = namespace);
}
PARSER(parse_extend) {
@@ -2139,8 +2016,7 @@ PARSER(parse_extend) {
int64_t starting_indent = get_indent(ctx, pos);
spaces(&pos);
const char *name = get_id(&pos);
- if (!name)
- parser_err(ctx, start, pos, "I expected a name for this lang");
+ if (!name) parser_err(ctx, start, pos, "I expected a name for this lang");
ast_t *body = NULL;
const char *ns_pos = pos;
@@ -2150,14 +2026,12 @@ PARSER(parse_extend) {
pos = ns_pos;
body = optional(ctx, &pos, parse_namespace);
}
- if (!body)
- body = NewAST(ctx->file, pos, pos, Block, .statements=NULL);
+ if (!body) body = NewAST(ctx->file, pos, pos, Block, .statements = NULL);
- return NewAST(ctx->file, start, pos, Extend, .name=name, .body=body);
+ return NewAST(ctx->file, start, pos, Extend, .name = name, .body = body);
}
-arg_ast_t *parse_args(parse_ctx_t *ctx, const char **pos)
-{
+arg_ast_t *parse_args(parse_ctx_t *ctx, const char **pos) {
arg_ast_t *args = NULL;
for (;;) {
const char *batch_start = *pos;
@@ -2177,18 +2051,18 @@ arg_ast_t *parse_args(parse_ctx_t *ctx, const char **pos)
whitespace(pos);
if (match(pos, ":")) {
- type = expect(ctx, *pos-1, pos, parse_type, "I expected a type here");
- names = new(name_list_t, .name=name, .next=names);
+ type = expect(ctx, *pos - 1, pos, parse_type, "I expected a type here");
+ names = new (name_list_t, .name = name, .next = names);
whitespace(pos);
if (match(pos, "="))
- default_val = expect(ctx, *pos-1, pos, parse_term, "I expected a value after this '='");
+ default_val = expect(ctx, *pos - 1, pos, parse_term, "I expected a value after this '='");
break;
} else if (strncmp(*pos, "==", 2) != 0 && match(pos, "=")) {
- default_val = expect(ctx, *pos-1, pos, parse_term, "I expected a value after this '='");
- names = new(name_list_t, .name=name, .next=names);
+ default_val = expect(ctx, *pos - 1, pos, parse_term, "I expected a value after this '='");
+ names = new (name_list_t, .name = name, .next = names);
break;
} else if (name) {
- names = new(name_list_t, .name=name, .next=names);
+ names = new (name_list_t, .name = name, .next = names);
spaces(pos);
if (!match(pos, ",")) break;
} else {
@@ -2197,14 +2071,15 @@ arg_ast_t *parse_args(parse_ctx_t *ctx, const char **pos)
}
if (!names) break;
if (!default_val && !type)
- parser_err(ctx, batch_start, *pos, "I expected a ':' and type, or '=' and a default value after this parameter (", names->name, ")");
+ parser_err(ctx, batch_start, *pos,
+ "I expected a ':' and type, or '=' and a default value after this parameter (", names->name,
+ ")");
REVERSE_LIST(names);
for (; names; names = names->next)
- args = new(arg_ast_t, .name=names->name, .type=type, .value=default_val, .next=args);
+ args = new (arg_ast_t, .name = names->name, .type = type, .value = default_val, .next = args);
- if (!match_separator(pos))
- break;
+ if (!match_separator(pos)) break;
}
REVERSE_LIST(args);
@@ -2233,22 +2108,19 @@ PARSER(parse_func_def) {
if (match_word(&pos, "inline")) {
is_inline = true;
} else if (match_word(&pos, "cached")) {
- if (!cache_ast) cache_ast = NewAST(ctx->file, pos, pos, Int, .str="-1");
+ if (!cache_ast) cache_ast = NewAST(ctx->file, pos, pos, Int, .str = "-1");
} else if (match_word(&pos, "cache_size")) {
whitespace(&pos);
- if (!match(&pos, "="))
- parser_err(ctx, flag_start, pos, "I expected a value for 'cache_size'");
+ if (!match(&pos, "=")) parser_err(ctx, flag_start, pos, "I expected a value for 'cache_size'");
whitespace(&pos);
cache_ast = expect(ctx, start, &pos, parse_expr, "I expected a maximum size for the cache");
}
}
expect_closing(ctx, &pos, ")", "I wasn't able to parse the rest of this function definition");
- ast_t *body = expect(ctx, start, &pos, parse_block,
- "This function needs a body block");
- return NewAST(ctx->file, start, pos, FunctionDef,
- .name=name, .args=args, .ret_type=ret_type, .body=body, .cache=cache_ast,
- .is_inline=is_inline);
+ ast_t *body = expect(ctx, start, &pos, parse_block, "This function needs a body block");
+ return NewAST(ctx->file, start, pos, FunctionDef, .name = name, .args = args, .ret_type = ret_type, .body = body,
+ .cache = cache_ast, .is_inline = is_inline);
}
PARSER(parse_convert_def) {
@@ -2270,33 +2142,30 @@ PARSER(parse_convert_def) {
if (match_word(&pos, "inline")) {
is_inline = true;
} else if (match_word(&pos, "cached")) {
- if (!cache_ast) cache_ast = NewAST(ctx->file, pos, pos, Int, .str="-1");
+ if (!cache_ast) cache_ast = NewAST(ctx->file, pos, pos, Int, .str = "-1");
} else if (match_word(&pos, "cache_size")) {
whitespace(&pos);
- if (!match(&pos, "="))
- parser_err(ctx, flag_start, pos, "I expected a value for 'cache_size'");
+ if (!match(&pos, "=")) parser_err(ctx, flag_start, pos, "I expected a value for 'cache_size'");
whitespace(&pos);
cache_ast = expect(ctx, start, &pos, parse_expr, "I expected a maximum size for the cache");
}
}
expect_closing(ctx, &pos, ")", "I wasn't able to parse the rest of this function definition");
- ast_t *body = expect(ctx, start, &pos, parse_block,
- "This function needs a body block");
- return NewAST(ctx->file, start, pos, ConvertDef,
- .args=args, .ret_type=ret_type, .body=body, .cache=cache_ast, .is_inline=is_inline);
+ ast_t *body = expect(ctx, start, &pos, parse_block, "This function needs a body block");
+ return NewAST(ctx->file, start, pos, ConvertDef, .args = args, .ret_type = ret_type, .body = body,
+ .cache = cache_ast, .is_inline = is_inline);
}
PARSER(parse_extern) {
const char *start = pos;
if (!match_word(&pos, "extern")) return NULL;
spaces(&pos);
- const char* name = get_id(&pos);
+ const char *name = get_id(&pos);
spaces(&pos);
- if (!match(&pos, ":"))
- parser_err(ctx, start, pos, "I couldn't get a type for this extern");
+ if (!match(&pos, ":")) parser_err(ctx, start, pos, "I couldn't get a type for this extern");
type_ast_t *type = expect(ctx, start, &pos, parse_type, "I couldn't parse the type for this extern");
- return NewAST(ctx->file, start, pos, Extern, .name=name, .type=type);
+ return NewAST(ctx->file, start, pos, Extern, .name = name, .type = type);
}
PARSER(parse_inline_c) {
@@ -2309,22 +2178,20 @@ PARSER(parse_inline_c) {
if (match(&pos, ":")) {
type = expect(ctx, start, &pos, parse_type, "I couldn't parse the type for this C_code code");
spaces(&pos);
- if (!match(&pos, "("))
- parser_err(ctx, start, pos, "I expected a '(' here");
- chunks = new(ast_list_t, .ast=NewAST(ctx->file, pos, pos, TextLiteral, Text("({")),
- .next=_parse_text_helper(ctx, &pos, '(', ')', '@', false));
+ if (!match(&pos, "(")) parser_err(ctx, start, pos, "I expected a '(' here");
+ chunks = new (ast_list_t, .ast = NewAST(ctx->file, pos, pos, TextLiteral, Text("({")),
+ .next = _parse_text_helper(ctx, &pos, '(', ')', '@', false));
if (type) {
REVERSE_LIST(chunks);
- chunks = new(ast_list_t, .ast=NewAST(ctx->file, pos, pos, TextLiteral, Text("; })")), .next=chunks);
+ chunks = new (ast_list_t, .ast = NewAST(ctx->file, pos, pos, TextLiteral, Text("; })")), .next = chunks);
REVERSE_LIST(chunks);
}
} else {
- if (!match(&pos, "{"))
- parser_err(ctx, start, pos, "I expected a '{' here");
+ if (!match(&pos, "{")) parser_err(ctx, start, pos, "I expected a '{' here");
chunks = _parse_text_helper(ctx, &pos, '{', '}', '@', false);
}
- return NewAST(ctx->file, start, pos, InlineCCode, .chunks=chunks, .type_ast=type);
+ return NewAST(ctx->file, start, pos, InlineCCode, .chunks = chunks, .type_ast = type);
}
PARSER(parse_doctest) {
@@ -2340,7 +2207,7 @@ PARSER(parse_doctest) {
} else {
pos = expr->end;
}
- return NewAST(ctx->file, start, pos, DocTest, .expr=expr, .expected=expected);
+ return NewAST(ctx->file, start, pos, DocTest, .expr = expr, .expected = expected);
}
PARSER(parse_assert) {
@@ -2356,7 +2223,7 @@ PARSER(parse_assert) {
} else {
pos = expr->end;
}
- return NewAST(ctx->file, start, pos, Assert, .expr=expr, .message=message);
+ return NewAST(ctx->file, start, pos, Assert, .expr = expr, .message = message);
}
PARSER(parse_use) {
@@ -2373,12 +2240,12 @@ PARSER(parse_use) {
if (!match_word(&pos, "use")) return NULL;
spaces(&pos);
size_t name_len = strcspn(pos, " \t\r\n;");
- if (name_len < 1)
- parser_err(ctx, start, pos, "There is no module name here to use");
+ if (name_len < 1) parser_err(ctx, start, pos, "There is no module name here to use");
char *name = GC_strndup(pos, name_len);
pos += name_len;
- while (match(&pos, ";")) continue;
- int what;
+ while (match(&pos, ";"))
+ continue;
+ int what;
if (name[0] == '<' || ends_with(name, ".h")) {
what = USE_HEADER;
} else if (starts_with(name, "-l")) {
@@ -2387,17 +2254,17 @@ PARSER(parse_use) {
what = USE_C_CODE;
} else if (ends_with(name, ".S") || ends_with(name, ".s")) {
what = USE_ASM;
- } else if (starts_with(name, "./") || starts_with(name, "/") || starts_with(name, "../") || starts_with(name, "~/")) {
+ } else if (starts_with(name, "./") || starts_with(name, "/") || starts_with(name, "../")
+ || starts_with(name, "~/")) {
what = USE_LOCAL;
} else {
what = USE_MODULE;
}
- return NewAST(ctx->file, start, pos, Use, .var=var, .path=name, .what=what);
+ return NewAST(ctx->file, start, pos, Use, .var = var, .path = name, .what = what);
}
ast_t *parse_file(const char *path, jmp_buf *on_err) {
- if (path[0] != '<' && path[0] != '/')
- fail("Path is not fully resolved: ", path);
+ if (path[0] != '<' && path[0] != '/') fail("Path is not fully resolved: ", path);
// NOTE: this cache leaks a bounded amount of memory. The cache will never
// hold more than PARSE_CACHE_SIZE entries (see below), but each entry's
// AST holds onto a reference to the file it came from, so they could
@@ -2417,8 +2284,8 @@ ast_t *parse_file(const char *path, jmp_buf *on_err) {
}
parse_ctx_t ctx = {
- .file=file,
- .on_err=on_err,
+ .file = file,
+ .on_err = on_err,
};
const char *pos = file->text;
@@ -2437,7 +2304,10 @@ ast_t *parse_file(const char *path, jmp_buf *on_err) {
if (cached.entries.length > PARSE_CACHE_SIZE) {
// FIXME: this currently evicts the first entry, but it should be more like
// an LRU cache
- struct {const char *path; ast_t *ast; } *to_remove = Table$entry(cached, 1);
+ struct {
+ const char *path;
+ ast_t *ast;
+ } *to_remove = Table$entry(cached, 1);
Table$str_remove(&cached, to_remove->path);
}
@@ -2449,8 +2319,8 @@ ast_t *parse_file(const char *path, jmp_buf *on_err) {
type_ast_t *parse_type_str(const char *str) {
file_t *file = spoof_file("<type>", str);
parse_ctx_t ctx = {
- .file=file,
- .on_err=NULL,
+ .file = file,
+ .on_err = NULL,
};
const char *pos = file->text;
@@ -2468,8 +2338,8 @@ type_ast_t *parse_type_str(const char *str) {
ast_t *parse(const char *str) {
file_t *file = spoof_file("<string>", str);
parse_ctx_t ctx = {
- .file=file,
- .on_err=NULL,
+ .file = file,
+ .on_err = NULL,
};
const char *pos = file->text;
@@ -2485,8 +2355,8 @@ ast_t *parse(const char *str) {
ast_t *parse_expression(const char *str) {
file_t *file = spoof_file("<string>", str);
parse_ctx_t ctx = {
- .file=file,
- .on_err=NULL,
+ .file = file,
+ .on_err = NULL,
};
const char *pos = file->text;
diff --git a/src/stdlib/bools.c b/src/stdlib/bools.c
index 76de49e0..0231e21b 100644
--- a/src/stdlib/bools.c
+++ b/src/stdlib/bools.c
@@ -11,18 +11,14 @@
#include "text.h"
#include "util.h"
-PUREFUNC public Text_t Bool$as_text(const void *b, bool colorize, const TypeInfo_t *info)
-{
+PUREFUNC public Text_t Bool$as_text(const void *b, bool colorize, const TypeInfo_t *info) {
(void)info;
if (!b) return Text("Bool");
- if (colorize)
- return *(Bool_t*)b ? Text("\x1b[35myes\x1b[m") : Text("\x1b[35mno\x1b[m");
- else
- return *(Bool_t*)b ? Text("yes") : Text("no");
+ if (colorize) return *(Bool_t *)b ? Text("\x1b[35myes\x1b[m") : Text("\x1b[35mno\x1b[m");
+ else return *(Bool_t *)b ? Text("yes") : Text("no");
}
-static bool try_parse(Text_t text, Text_t target, bool target_value, Text_t *remainder, bool *result)
-{
+static bool try_parse(Text_t text, Text_t target, bool target_value, Text_t *remainder, bool *result) {
static const Text_t lang = Text("C");
if (text.length < target.length) return false;
Text_t prefix = Text$to(text, Int$from_int64(target.length));
@@ -36,35 +32,33 @@ static bool try_parse(Text_t text, Text_t target, bool target_value, Text_t *rem
}
}
-PUREFUNC public OptionalBool_t Bool$parse(Text_t text, Text_t *remainder)
-{
+PUREFUNC public OptionalBool_t Bool$parse(Text_t text, Text_t *remainder) {
bool result;
if (try_parse(text, Text("yes"), true, remainder, &result)
|| try_parse(text, Text("true"), true, remainder, &result)
- || try_parse(text, Text("on"), true, remainder, &result)
- || try_parse(text, Text("1"), true, remainder, &result)
+ || try_parse(text, Text("on"), true, remainder, &result) || try_parse(text, Text("1"), true, remainder, &result)
|| try_parse(text, Text("no"), false, remainder, &result)
|| try_parse(text, Text("false"), false, remainder, &result)
|| try_parse(text, Text("off"), false, remainder, &result)
|| try_parse(text, Text("0"), false, remainder, &result))
return result;
- else
- return NONE_BOOL;
+ else return NONE_BOOL;
}
-static bool Bool$is_none(const void *b, const TypeInfo_t *info)
-{
+static bool Bool$is_none(const void *b, const TypeInfo_t *info) {
(void)info;
- return *(OptionalBool_t*)b == NONE_BOOL;
+ return *(OptionalBool_t *)b == NONE_BOOL;
}
-public const TypeInfo_t Bool$info = {
- .size=sizeof(bool),
- .align=__alignof__(bool),
- .metamethods={
- .as_text=Bool$as_text,
- .is_none=Bool$is_none,
- },
+public
+const TypeInfo_t Bool$info = {
+ .size = sizeof(bool),
+ .align = __alignof__(bool),
+ .metamethods =
+ {
+ .as_text = Bool$as_text,
+ .is_none = Bool$is_none,
+ },
};
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/stdlib/bools.h b/src/stdlib/bools.h
index bdf80879..3eac0f0d 100644
--- a/src/stdlib/bools.h
+++ b/src/stdlib/bools.h
@@ -8,8 +8,8 @@
#include "types.h"
#include "util.h"
-#define yes (Bool_t)true
-#define no (Bool_t)false
+#define yes (Bool_t) true
+#define no (Bool_t) false
PUREFUNC Text_t Bool$as_text(const void *b, bool colorize, const TypeInfo_t *type);
OptionalBool_t Bool$parse(Text_t text, Text_t *remainder);
diff --git a/src/stdlib/bytes.c b/src/stdlib/bytes.c
index 5a581e7e..d4bd5ef6 100644
--- a/src/stdlib/bytes.c
+++ b/src/stdlib/bytes.c
@@ -8,15 +8,18 @@
#include "text.h"
#include "util.h"
-public const Byte_t Byte$min = 0;
-public const Byte_t Byte$max = UINT8_MAX;
+public
+const Byte_t Byte$min = 0;
+public
+const Byte_t Byte$max = UINT8_MAX;
-PUREFUNC public Text_t Byte$as_text(const void *b, bool colorize, const TypeInfo_t *info)
-{
+PUREFUNC public Text_t Byte$as_text(const void *b, bool colorize, const TypeInfo_t *info) {
(void)info;
if (!b) return Text("Byte");
- Byte_t byte = *(Byte_t*)b;
- char digits[] = {'0', 'x',
+ Byte_t byte = *(Byte_t *)b;
+ char digits[] = {
+ '0',
+ 'x',
(byte / 16) <= 9 ? '0' + (byte / 16) : 'a' + (byte / 16) - 10,
(byte & 15) <= 9 ? '0' + (byte & 15) : 'a' + (byte & 15) - 10,
'\0',
@@ -26,52 +29,54 @@ PUREFUNC public Text_t Byte$as_text(const void *b, bool colorize, const TypeInfo
return text;
}
-public CONSTFUNC bool Byte$is_between(const Byte_t x, const Byte_t low, const Byte_t high) {
- return low <= x && x <= high;
-}
+public
+CONSTFUNC bool Byte$is_between(const Byte_t x, const Byte_t low, const Byte_t high) { return low <= x && x <= high; }
-public OptionalByte_t Byte$parse(Text_t text, Text_t *remainder)
-{
+public
+OptionalByte_t Byte$parse(Text_t text, Text_t *remainder) {
OptionalInt_t full_int = Int$parse(text, remainder);
- if (full_int.small != 0L
- && Int$compare_value(full_int, I(0)) >= 0
- && Int$compare_value(full_int, I(255)) <= 0) {
- return (OptionalByte_t){.value=Byte$from_int(full_int, true)};
+ if (full_int.small != 0L && Int$compare_value(full_int, I(0)) >= 0 && Int$compare_value(full_int, I(255)) <= 0) {
+ return (OptionalByte_t){.value = Byte$from_int(full_int, true)};
} else {
return NONE_BYTE;
}
}
-public Text_t Byte$hex(Byte_t byte, bool uppercase, bool prefix) {
- struct Text_s text = {.tag=TEXT_ASCII};
+public
+Text_t Byte$hex(Byte_t byte, bool uppercase, bool prefix) {
+ struct Text_s text = {.tag = TEXT_ASCII};
text.ascii = GC_MALLOC_ATOMIC(8);
- char *p = (char*)text.ascii;
+ char *p = (char *)text.ascii;
if (prefix) {
*(p++) = '0';
*(p++) = 'x';
}
if (uppercase) {
- *(p++) = (byte/16) > 9 ? 'A' + (byte/16) - 10 : '0' + (byte/16);
+ *(p++) = (byte / 16) > 9 ? 'A' + (byte / 16) - 10 : '0' + (byte / 16);
*(p++) = (byte & 15) > 9 ? 'A' + (byte & 15) - 10 : '0' + (byte & 15);
} else {
- *(p++) = (byte/16) > 9 ? 'a' + (byte/16) - 10 : '0' + (byte/16);
+ *(p++) = (byte / 16) > 9 ? 'a' + (byte / 16) - 10 : '0' + (byte / 16);
*(p++) = (byte & 15) > 9 ? 'a' + (byte & 15) - 10 : '0' + (byte & 15);
}
text.length = (int64_t)(p - text.ascii);
return text;
}
-public bool Byte$get_bit(Byte_t x, Int_t bit_index) {
- if (Int$compare_value(bit_index, I(1)) < 0)
- fail("Invalid bit index (expected 1 or higher): ", bit_index);
+public
+bool Byte$get_bit(Byte_t x, Int_t bit_index) {
+ if (Int$compare_value(bit_index, I(1)) < 0) fail("Invalid bit index (expected 1 or higher): ", bit_index);
if (Int$compare_value(bit_index, I(8)) > 0)
fail("Bit index is too large! There are only 8 bits in a byte, but index is: ", bit_index);
- return ((x & (Byte_t)(1L << (Int64$from_int(bit_index, true)-1L))) != 0);
+ return ((x & (Byte_t)(1L << (Int64$from_int(bit_index, true) - 1L))) != 0);
}
#ifdef __TINYC__
-#define __builtin_add_overflow(x, y, result) ({ *(result) = (x) + (y); false; })
+#define __builtin_add_overflow(x, y, result) \
+ ({ \
+ *(result) = (x) + (y); \
+ false; \
+ })
#endif
typedef struct {
@@ -82,52 +87,59 @@ typedef struct {
static OptionalByte_t _next_Byte(ByteRange_t *info) {
OptionalByte_t i = info->current;
if (!i.is_none) {
- Byte_t next; bool overflow = __builtin_add_overflow(i.value, info->step, &next);
+ Byte_t next;
+ bool overflow = __builtin_add_overflow(i.value, info->step, &next);
if (overflow || (!info->last.is_none && (info->step >= 0 ? next > info->last.value : next < info->last.value)))
- info->current = (OptionalByte_t){.is_none=true};
- else
- info->current = (OptionalByte_t){.value=next};
+ info->current = (OptionalByte_t){.is_none = true};
+ else info->current = (OptionalByte_t){.value = next};
}
return i;
}
-public CONSTFUNC Closure_t Byte$to(Byte_t first, Byte_t last, OptionalInt8_t step) {
+public
+CONSTFUNC Closure_t Byte$to(Byte_t first, Byte_t last, OptionalInt8_t step) {
ByteRange_t *range = GC_MALLOC(sizeof(ByteRange_t));
- range->current = (OptionalByte_t){.value=first};
- range->last = (OptionalByte_t){.value=last};
+ range->current = (OptionalByte_t){.value = first};
+ range->last = (OptionalByte_t){.value = last};
range->step = step.is_none ? (last >= first ? 1 : -1) : step.value;
- return (Closure_t){.fn=_next_Byte, .userdata=range};
+ return (Closure_t){.fn = _next_Byte, .userdata = range};
}
-public PUREFUNC Byte_t Byte$from_int(Int_t i, bool truncate) {
+public
+PUREFUNC Byte_t Byte$from_int(Int_t i, bool truncate) {
if unlikely (!truncate && Int$compare_value(i, I_small(0xFF)) > 0)
fail("This value is too large to convert to a byte without truncation: ", i);
else if unlikely (!truncate && Int$compare_value(i, I_small(0)) < 0)
fail("Negative values can't be converted to bytes: ", i);
return (Byte_t)(i.small >> 2);
}
-public PUREFUNC Byte_t Byte$from_int64(Int64_t i, bool truncate) {
+public
+PUREFUNC Byte_t Byte$from_int64(Int64_t i, bool truncate) {
if unlikely (!truncate && i != (Int64_t)(Byte_t)i)
fail("This value can't be converted to a byte without truncation: ", i);
return (Byte_t)i;
}
-public PUREFUNC Byte_t Byte$from_int32(Int32_t i, bool truncate) {
+public
+PUREFUNC Byte_t Byte$from_int32(Int32_t i, bool truncate) {
if unlikely (!truncate && i != (Int32_t)(Byte_t)i)
fail("This value can't be converted to a byte without truncation: ", i);
return (Byte_t)i;
}
-public PUREFUNC Byte_t Byte$from_int16(Int16_t i, bool truncate) {
+public
+PUREFUNC Byte_t Byte$from_int16(Int16_t i, bool truncate) {
if unlikely (!truncate && i != (Int16_t)(Byte_t)i)
fail("This value can't be converted to a byte without truncation: ", i);
return (Byte_t)i;
}
-public const TypeInfo_t Byte$info = {
- .size=sizeof(Byte_t),
- .align=__alignof__(Byte_t),
- .metamethods={
- .as_text=Byte$as_text,
- },
+public
+const TypeInfo_t Byte$info = {
+ .size = sizeof(Byte_t),
+ .align = __alignof__(Byte_t),
+ .metamethods =
+ {
+ .as_text = Byte$as_text,
+ },
};
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/stdlib/c_strings.c b/src/stdlib/c_strings.c
index c2b8efbe..b965f04b 100644
--- a/src/stdlib/c_strings.c
+++ b/src/stdlib/c_strings.c
@@ -12,46 +12,40 @@
#include "text.h"
#include "util.h"
-public Text_t CString$as_text(const void *c_string, bool colorize, const TypeInfo_t *info)
-{
+public
+Text_t CString$as_text(const void *c_string, bool colorize, const TypeInfo_t *info) {
(void)info;
if (!c_string) return Text("CString");
- Text_t text = Text$from_str(*(const char**)c_string);
- return Text$concat(colorize ? Text("\x1b[34mCString\x1b[m(") : Text("CString("), Text$quoted(text, colorize, Text("\"")), Text(")"));
+ Text_t text = Text$from_str(*(const char **)c_string);
+ return Text$concat(colorize ? Text("\x1b[34mCString\x1b[m(") : Text("CString("),
+ Text$quoted(text, colorize, Text("\"")), Text(")"));
}
-PUREFUNC public int32_t CString$compare(const void *x, const void *y, const TypeInfo_t *info)
-{
+PUREFUNC public int32_t CString$compare(const void *x, const void *y, const TypeInfo_t *info) {
(void)info;
- if (x == y)
- return 0;
+ if (x == y) return 0;
- if (!*(const char**)x != !*(const char**)y)
- return (!*(const char**)y) - (!*(const char**)x);
+ if (!*(const char **)x != !*(const char **)y) return (!*(const char **)y) - (!*(const char **)x);
- return strcmp(*(const char**)x, *(const char**)y);
+ return strcmp(*(const char **)x, *(const char **)y);
}
-PUREFUNC public bool CString$equal(const void *x, const void *y, const TypeInfo_t *type)
-{
+PUREFUNC public bool CString$equal(const void *x, const void *y, const TypeInfo_t *type) {
return CString$compare(x, y, type) == 0;
}
-PUREFUNC public uint64_t CString$hash(const void *c_str, const TypeInfo_t *info)
-{
+PUREFUNC public uint64_t CString$hash(const void *c_str, const TypeInfo_t *info) {
(void)info;
- if (!*(const char**)c_str) return 0;
- return siphash24(*(void**)c_str, strlen(*(const char**)c_str));
+ if (!*(const char **)c_str) return 0;
+ return siphash24(*(void **)c_str, strlen(*(const char **)c_str));
}
-PUREFUNC public bool CString$is_none(const void *c_str, const TypeInfo_t *info)
-{
+PUREFUNC public bool CString$is_none(const void *c_str, const TypeInfo_t *info) {
(void)info;
- return *(const char**)c_str == NULL;
+ return *(const char **)c_str == NULL;
}
-static void CString$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *info)
-{
+static void CString$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *info) {
(void)info;
const char *str = *(const char **)obj;
int64_t len = (int64_t)strlen(str);
@@ -59,30 +53,30 @@ static void CString$serialize(const void *obj, FILE *out, Table_t *pointers, con
fwrite(str, sizeof(char), (size_t)len, out);
}
-static void CString$deserialize(FILE *in, void *out, List_t *pointers, const TypeInfo_t *info)
-{
+static void CString$deserialize(FILE *in, void *out, List_t *pointers, const TypeInfo_t *info) {
(void)info;
int64_t len = -1;
Int64$deserialize(in, &len, pointers, &Int64$info);
- char *str = GC_MALLOC_ATOMIC((size_t)len+1);
- if (fread(str, sizeof(char), (size_t)len, in) != (size_t)len)
- fail("Not enough data in stream to deserialize");
- str[len+1] = '\0';
- *(const char**)out = str;
+ char *str = GC_MALLOC_ATOMIC((size_t)len + 1);
+ if (fread(str, sizeof(char), (size_t)len, in) != (size_t)len) fail("Not enough data in stream to deserialize");
+ str[len + 1] = '\0';
+ *(const char **)out = str;
}
-public const TypeInfo_t CString$info = {
- .size=sizeof(const char*),
- .align=__alignof__(const char*),
- .metamethods={
- .hash=CString$hash,
- .compare=CString$compare,
- .equal=CString$equal,
- .as_text=CString$as_text,
- .is_none=CString$is_none,
- .serialize=CString$serialize,
- .deserialize=CString$deserialize,
- },
+public
+const TypeInfo_t CString$info = {
+ .size = sizeof(const char *),
+ .align = __alignof__(const char *),
+ .metamethods =
+ {
+ .hash = CString$hash,
+ .compare = CString$compare,
+ .equal = CString$equal,
+ .as_text = CString$as_text,
+ .is_none = CString$is_none,
+ .serialize = CString$serialize,
+ .deserialize = CString$deserialize,
+ },
};
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/stdlib/datatypes.h b/src/stdlib/datatypes.h
index e473956e..5d016246 100644
--- a/src/stdlib/datatypes.h
+++ b/src/stdlib/datatypes.h
@@ -12,9 +12,9 @@
#define LIST_REFCOUNT_BITS 3
#define LIST_STRIDE_BITS 12
-#define MAX_FOR_N_BITS(N) ((1L<<(N))-1L)
-#define LIST_MAX_STRIDE MAX_FOR_N_BITS(LIST_STRIDE_BITS-1)
-#define LIST_MIN_STRIDE (~MAX_FOR_N_BITS(LIST_STRIDE_BITS-1))
+#define MAX_FOR_N_BITS(N) ((1L << (N)) - 1L)
+#define LIST_MAX_STRIDE MAX_FOR_N_BITS(LIST_STRIDE_BITS - 1)
+#define LIST_MIN_STRIDE (~MAX_FOR_N_BITS(LIST_STRIDE_BITS - 1))
#define LIST_MAX_DATA_REFCOUNT MAX_FOR_N_BITS(LIST_REFCOUNT_BITS)
#define LIST_MAX_FREE_ENTRIES MAX_FOR_N_BITS(LIST_FREE_BITS)
@@ -41,15 +41,15 @@ typedef struct {
// structs can be passed in two 64-bit registers. C will handle doing the
// bit arithmetic to extract the necessary values, which is cheaper than
// spilling onto the stack and needing to retrieve data from the stack.
- int64_t length:LIST_LENGTH_BITS;
- uint64_t free:LIST_FREE_BITS;
- bool atomic:LIST_ATOMIC_BITS;
- uint8_t data_refcount:LIST_REFCOUNT_BITS;
- int16_t stride:LIST_STRIDE_BITS;
+ int64_t length : LIST_LENGTH_BITS;
+ uint64_t free : LIST_FREE_BITS;
+ bool atomic : LIST_ATOMIC_BITS;
+ uint8_t data_refcount : LIST_REFCOUNT_BITS;
+ int16_t stride : LIST_STRIDE_BITS;
} List_t;
typedef struct {
- uint32_t occupied:1, index:31;
+ uint32_t occupied : 1, index : 31;
uint32_t next_bucket;
} bucket_t;
@@ -57,8 +57,8 @@ typedef struct {
#define TABLE_MAX_DATA_REFCOUNT 3
typedef struct {
- uint32_t count:31, last_free:31;
- uint8_t data_refcount:2;
+ uint32_t count : 31, last_free : 31;
+ uint8_t data_refcount : 2;
bucket_t buckets[];
} bucket_info_t;
@@ -76,9 +76,9 @@ typedef struct {
enum text_type { TEXT_ASCII, TEXT_GRAPHEMES, TEXT_CONCAT, TEXT_BLOB };
typedef struct Text_s {
- int64_t length:54; // Number of grapheme clusters
- uint8_t tag:2;
- uint8_t depth:8;
+ int64_t length : 54; // Number of grapheme clusters
+ uint8_t tag : 2;
+ uint8_t depth : 8;
union {
struct {
const char *ascii;
@@ -117,10 +117,9 @@ typedef struct {
typedef struct {
Byte_t value;
- bool is_none:1;
+ bool is_none : 1;
} OptionalByte_t;
-#define NONE_BYTE ((OptionalByte_t){.is_none=true})
-
+#define NONE_BYTE ((OptionalByte_t){.is_none = true})
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/stdlib/enums.c b/src/stdlib/enums.c
index ae0c976d..7f7c4284 100644
--- a/src/stdlib/enums.c
+++ b/src/stdlib/enums.c
@@ -11,34 +11,30 @@
CONSTFUNC static ptrdiff_t value_offset(const TypeInfo_t *type) {
ptrdiff_t offset = sizeof(int32_t);
for (int i = 0; i < type->EnumInfo.num_tags; i++) {
- if (type->EnumInfo.tags[i].type)
- offset = MAX(offset, type->EnumInfo.tags[i].type->align);
+ if (type->EnumInfo.tags[i].type) offset = MAX(offset, type->EnumInfo.tags[i].type->align);
}
return offset;
}
-PUREFUNC public uint64_t Enum$hash(const void *obj, const TypeInfo_t *type)
-{
- int32_t tag = *(int32_t*)obj;
+PUREFUNC public uint64_t Enum$hash(const void *obj, const TypeInfo_t *type) {
+ int32_t tag = *(int32_t *)obj;
uint32_t components[2] = {(uint32_t)tag, 0};
- const TypeInfo_t *value = type->EnumInfo.tags[tag-1].type;
+ const TypeInfo_t *value = type->EnumInfo.tags[tag - 1].type;
if (value && value->size > 0) {
components[1] = generic_hash(obj + value_offset(type), value);
}
- return siphash24((void*)components, sizeof(components));
+ return siphash24((void *)components, sizeof(components));
}
-PUREFUNC public int32_t Enum$compare(const void *x, const void *y, const TypeInfo_t *type)
-{
+PUREFUNC public int32_t Enum$compare(const void *x, const void *y, const TypeInfo_t *type) {
if (x == y) return 0;
- int32_t x_tag = *(int32_t*)x;
- int32_t y_tag = *(int32_t*)y;
- if (x_tag != y_tag)
- return x_tag > y_tag ? 1 : -1;
+ int32_t x_tag = *(int32_t *)x;
+ int32_t y_tag = *(int32_t *)y;
+ if (x_tag != y_tag) return x_tag > y_tag ? 1 : -1;
- const TypeInfo_t *value = type->EnumInfo.tags[x_tag-1].type;
+ const TypeInfo_t *value = type->EnumInfo.tags[x_tag - 1].type;
if (value && value->size > 0) {
ptrdiff_t byte_offset = value_offset(type);
return generic_compare(x + byte_offset, y + byte_offset, value);
@@ -46,16 +42,14 @@ PUREFUNC public int32_t Enum$compare(const void *x, const void *y, const TypeInf
return 0;
}
-PUREFUNC public bool Enum$equal(const void *x, const void *y, const TypeInfo_t *type)
-{
+PUREFUNC public bool Enum$equal(const void *x, const void *y, const TypeInfo_t *type) {
if (x == y) return true;
- int32_t x_tag = *(int32_t*)x;
- int32_t y_tag = *(int32_t*)y;
- if (x_tag != y_tag)
- return false;
+ int32_t x_tag = *(int32_t *)x;
+ int32_t y_tag = *(int32_t *)y;
+ if (x_tag != y_tag) return false;
- const TypeInfo_t *value = type->EnumInfo.tags[x_tag-1].type;
+ const TypeInfo_t *value = type->EnumInfo.tags[x_tag - 1].type;
if (value && value->size > 0) {
ptrdiff_t byte_offset = value_offset(type);
return generic_equal(x + byte_offset, y + byte_offset, value);
@@ -63,12 +57,12 @@ PUREFUNC public bool Enum$equal(const void *x, const void *y, const TypeInfo_t *
return true;
}
-public Text_t Enum$as_text(const void *obj, bool colorize, const TypeInfo_t *type)
-{
+public
+Text_t Enum$as_text(const void *obj, bool colorize, const TypeInfo_t *type) {
if (!obj) return Text$from_str(type->EnumInfo.name);
- int32_t tag = *(int32_t*)obj;
- NamedType_t value = type->EnumInfo.tags[tag-1];
+ int32_t tag = *(int32_t *)obj;
+ NamedType_t value = type->EnumInfo.tags[tag - 1];
if (!value.type || value.type->size == 0) {
Text_t text = Text$from_str(value.name);
return colorize ? Texts(Text("\x1b[1m"), text, Text("\x1b[m")) : text;
@@ -77,30 +71,29 @@ public Text_t Enum$as_text(const void *obj, bool colorize, const TypeInfo_t *typ
return generic_as_text(obj + value_offset(type), colorize, value.type);
}
-PUREFUNC public bool Enum$is_none(const void *x, const TypeInfo_t *info)
-{
+PUREFUNC public bool Enum$is_none(const void *x, const TypeInfo_t *info) {
(void)info;
- return *(int32_t*)x == 0;
+ return *(int32_t *)x == 0;
}
-public void Enum$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type)
-{
- int32_t tag = *(int32_t*)obj;
+public
+void Enum$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type) {
+ int32_t tag = *(int32_t *)obj;
Int32$serialize(&tag, out, pointers, &Int32$info);
- NamedType_t value = type->EnumInfo.tags[tag-1];
+ NamedType_t value = type->EnumInfo.tags[tag - 1];
if (value.type && value.type->size > 0) {
_serialize(obj + value_offset(type), out, pointers, value.type);
}
}
-public void Enum$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *type)
-{
+public
+void Enum$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *type) {
int32_t tag = 0;
Int32$deserialize(in, &tag, pointers, &Int32$info);
- *(int32_t*)outval = tag;
+ *(int32_t *)outval = tag;
- NamedType_t value = type->EnumInfo.tags[tag-1];
+ NamedType_t value = type->EnumInfo.tags[tag - 1];
if (value.type && value.type->size > 0) {
_deserialize(in, outval + value_offset(type), pointers, value.type);
}
diff --git a/src/stdlib/enums.h b/src/stdlib/enums.h
index 8345c527..99a0f615 100644
--- a/src/stdlib/enums.h
+++ b/src/stdlib/enums.h
@@ -15,24 +15,26 @@ PUREFUNC bool Enum$is_none(const void *obj, const TypeInfo_t *type);
void Enum$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type);
void Enum$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *type);
-#define Enum$metamethods { \
- .as_text=Enum$as_text, \
- .compare=Enum$compare, \
- .equal=Enum$equal, \
- .hash=Enum$hash, \
- .is_none=Enum$is_none, \
- .serialize=Enum$serialize, \
- .deserialize=Enum$deserialize, \
-}
+#define Enum$metamethods \
+ { \
+ .as_text = Enum$as_text, \
+ .compare = Enum$compare, \
+ .equal = Enum$equal, \
+ .hash = Enum$hash, \
+ .is_none = Enum$is_none, \
+ .serialize = Enum$serialize, \
+ .deserialize = Enum$deserialize, \
+ }
-#define PackedDataEnum$metamethods { \
- .hash=PackedData$hash, \
- .compare=Enum$compare, \
- .equal=PackedData$equal, \
- .as_text=Enum$as_text, \
- .is_none=Enum$is_none, \
- .serialize=Enum$serialize, \
- .deserialize=Enum$deserialize, \
-}
+#define PackedDataEnum$metamethods \
+ { \
+ .hash = PackedData$hash, \
+ .compare = Enum$compare, \
+ .equal = PackedData$equal, \
+ .as_text = Enum$as_text, \
+ .is_none = Enum$is_none, \
+ .serialize = Enum$serialize, \
+ .deserialize = Enum$deserialize, \
+ }
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/stdlib/files.c b/src/stdlib/files.c
index 87b0205c..08023e0e 100644
--- a/src/stdlib/files.c
+++ b/src/stdlib/files.c
@@ -20,8 +20,8 @@
static const int tabstop = 4;
-public char *resolve_path(const char *path, const char *relative_to, const char *system_path)
-{
+public
+char *resolve_path(const char *path, const char *relative_to, const char *system_path) {
if (!relative_to || streq(relative_to, "/dev/stdin")) relative_to = ".";
if (!path || strlen(path) == 0) return NULL;
@@ -29,7 +29,7 @@ public char *resolve_path(const char *path, const char *relative_to, const char
// it was found in:
char buf[PATH_MAX] = {0};
if (streq(path, "~") || starts_with(path, "~/")) {
- char *resolved = realpath(String(getenv("HOME"), path+1), buf);
+ char *resolved = realpath(String(getenv("HOME"), path + 1), buf);
if (resolved) return GC_strdup(resolved);
} else if (streq(path, ".") || starts_with(path, "./") || starts_with(path, "../")) {
char *relative_dir = dirname(GC_strdup(relative_to));
@@ -49,12 +49,13 @@ public char *resolve_path(const char *path, const char *relative_to, const char
char *resolved = realpath(String(dir, "/", path), buf);
if (resolved) return GC_strdup(resolved);
} else if (dir[0] == '~' && (dir[1] == '\0' || dir[1] == '/')) {
- char *resolved = realpath(String(getenv("HOME"), dir+1, "/", path), buf);
+ char *resolved = realpath(String(getenv("HOME"), dir + 1, "/", path), buf);
if (resolved) return GC_strdup(resolved);
} else if (streq(dir, ".") || strncmp(dir, "./", 2) == 0) {
char *resolved = realpath(String(relative_dir, "/", path), buf);
if (resolved) return GC_strdup(resolved);
- } else if (streq(dir, ".") || streq(dir, "..") || strncmp(dir, "./", 2) == 0 || strncmp(dir, "../", 3) == 0) {
+ } else if (streq(dir, ".") || streq(dir, "..") || strncmp(dir, "./", 2) == 0
+ || strncmp(dir, "../", 3) == 0) {
char *resolved = realpath(String(relative_dir, "/", dir, "/", path), buf);
if (resolved) return GC_strdup(resolved);
} else {
@@ -66,24 +67,23 @@ public char *resolve_path(const char *path, const char *relative_to, const char
return NULL;
}
-public char *file_base_name(const char *path)
-{
+public
+char *file_base_name(const char *path) {
const char *slash = strrchr(path, '/');
if (slash) path = slash + 1;
assert(!isdigit(*path));
const char *end = path + strcspn(path, ".");
size_t len = (size_t)(end - path);
- char *buf = GC_MALLOC_ATOMIC(len+1);
+ char *buf = GC_MALLOC_ATOMIC(len + 1);
strncpy(buf, path, len);
buf[len] = '\0';
return buf;
}
-static file_t *_load_file(const char* filename, FILE *file)
-{
+static file_t *_load_file(const char *filename, FILE *file) {
if (!file) return NULL;
- file_t *ret = new(file_t, .filename=filename);
+ file_t *ret = new (file_t, .filename = filename);
size_t file_size = 0, line_cap = 0;
char *file_buf = NULL, *line_buf = NULL;
@@ -98,7 +98,7 @@ static file_t *_load_file(const char* filename, FILE *file)
}
fclose(file);
- char *copy = GC_MALLOC_ATOMIC(file_size+1);
+ char *copy = GC_MALLOC_ATOMIC(file_size + 1);
memcpy(copy, file_buf, file_size);
copy[file_size] = '\0';
ret->text = copy;
@@ -114,7 +114,7 @@ static file_t *_load_file(const char* filename, FILE *file)
char *cwd = getcwd(buf, sizeof(buf));
size_t cwd_len = strlen(cwd);
if (strncmp(cwd, filename, cwd_len) == 0 && filename[cwd_len] == '/')
- ret->relative_filename = &filename[cwd_len+1];
+ ret->relative_filename = &filename[cwd_len + 1];
}
return ret;
}
@@ -122,8 +122,8 @@ static file_t *_load_file(const char* filename, FILE *file)
//
// Read an entire file into memory.
//
-public file_t *load_file(const char* filename)
-{
+public
+file_t *load_file(const char *filename) {
FILE *file = filename[0] ? fopen(filename, "r") : stdin;
return _load_file(filename, file);
}
@@ -131,30 +131,27 @@ public file_t *load_file(const char* filename)
//
// Create a virtual file from a string.
//
-public file_t *spoof_file(const char* filename, const char *text)
-{
- FILE *file = fmemopen((char*)text, strlen(text)+1, "r");
+public
+file_t *spoof_file(const char *filename, const char *text) {
+ FILE *file = fmemopen((char *)text, strlen(text) + 1, "r");
return _load_file(filename, file);
}
//
// Given a pointer, determine which line number it points to (1-indexed)
//
-public int64_t get_line_number(file_t *f, const char *p)
-{
+public
+int64_t get_line_number(file_t *f, const char *p) {
// Binary search:
- int64_t lo = 0, hi = (int64_t)f->num_lines-1;
+ int64_t lo = 0, hi = (int64_t)f->num_lines - 1;
if (p < f->text) return 0;
int64_t offset = (int64_t)(p - f->text);
while (lo <= hi) {
int64_t mid = (lo + hi) / 2;
int64_t line_offset = f->line_offsets[mid];
- if (line_offset == offset)
- return mid + 1;
- else if (line_offset < offset)
- lo = mid + 1;
- else if (line_offset > offset)
- hi = mid - 1;
+ if (line_offset == offset) return mid + 1;
+ else if (line_offset < offset) lo = mid + 1;
+ else if (line_offset > offset) hi = mid - 1;
}
return lo; // Return the line number whose line starts closest before p
}
@@ -162,33 +159,32 @@ public int64_t get_line_number(file_t *f, const char *p)
//
// Given a pointer, determine which line column it points to.
//
-public int64_t get_line_column(file_t *f, const char *p)
-{
+public
+int64_t get_line_column(file_t *f, const char *p) {
int64_t line_no = get_line_number(f, p);
- int64_t line_offset = f->line_offsets[line_no-1];
+ int64_t line_offset = f->line_offsets[line_no - 1];
return 1 + (int64_t)(p - (f->text + line_offset));
}
//
// Return a pointer to the line with the specified line number (1-indexed)
//
-public const char *get_line(file_t *f, int64_t line_number)
-{
+public
+const char *get_line(file_t *f, int64_t line_number) {
if (line_number == 0 || line_number > (int64_t)f->num_lines) return NULL;
- int64_t line_offset = f->line_offsets[line_number-1];
+ int64_t line_offset = f->line_offsets[line_number - 1];
return f->text + line_offset;
}
//
// Return a value like /foo:line.col
//
-public const char *get_file_pos(file_t *f, const char *p)
-{
+public
+const char *get_file_pos(file_t *f, const char *p) {
return String(f->filename, ":", get_line_number(f, p), ".", get_line_column(f, p));
}
-static int fputc_column(FILE *out, char c, char print_char, int *column)
-{
+static int fputc_column(FILE *out, char c, char print_char, int *column) {
int printed = 0;
if (print_char == '\t') print_char = ' ';
if (c == '\t') {
@@ -206,18 +202,16 @@ static int fputc_column(FILE *out, char c, char print_char, int *column)
//
// Print a span from a file
//
-public int highlight_error(file_t *file, const char *start, const char *end, const char *hl_color, int64_t context_lines, bool use_color)
-{
+public
+int highlight_error(file_t *file, const char *start, const char *end, const char *hl_color, int64_t context_lines,
+ bool use_color) {
if (!file) return 0;
// Handle spans that come from multiple files:
- if (start < file->text || start > file->text + file->len)
- start = end;
- if (end < file->text || end > file->text + file->len)
- end = start;
+ if (start < file->text || start > file->text + file->len) start = end;
+ if (end < file->text || end > file->text + file->len) end = start;
// Just in case neither end of the span came from this file:
- if (end < file->text || end > file->text + file->len)
- start = end = file->text;
+ if (end < file->text || end > file->text + file->len) start = end = file->text;
const char *lineno_prefix, *lineno_suffix, *normal_color, *empty_marker;
bool print_carets = false;
@@ -238,27 +232,25 @@ public int highlight_error(file_t *file, const char *start, const char *end, con
printed += fprint(stderr, file->relative_filename);
}
- if (context_lines == 0)
- return fprint(stderr, hl_color, string_slice(start, (size_t)(end - start)), normal_color);
+ if (context_lines == 0) return fprint(stderr, hl_color, string_slice(start, (size_t)(end - start)), normal_color);
- int64_t start_line = get_line_number(file, start),
- end_line = get_line_number(file, end);
+ int64_t start_line = get_line_number(file, start), end_line = get_line_number(file, end);
- int64_t first_line = start_line - (context_lines - 1),
- last_line = end_line + (context_lines - 1);
+ int64_t first_line = start_line - (context_lines - 1), last_line = end_line + (context_lines - 1);
if (first_line < 1) first_line = 1;
if (last_line > file->num_lines) last_line = file->num_lines;
int digits = 1;
- for (int64_t i = last_line; i > 0; i /= 10) ++digits;
+ for (int64_t i = last_line; i > 0; i /= 10)
+ ++digits;
for (int64_t line_no = first_line; line_no <= last_line; ++line_no) {
if (line_no > first_line + 5 && line_no < last_line - 5) {
if (use_color)
- printed += fprint(stderr, "\x1b[0;2;3;4m ... ", (last_line - first_line) - 11, " lines omitted ... \x1b[m");
- else
- printed += fprint(stderr, " ... ", (last_line - first_line) - 11, " lines omitted ...");
+ printed += fprint(stderr, "\x1b[0;2;3;4m ... ", (last_line - first_line) - 11,
+ " lines omitted ... \x1b[m");
+ else printed += fprint(stderr, " ... ", (last_line - first_line) - 11, " lines omitted ...");
line_no = last_line - 6;
continue;
}
@@ -305,14 +297,10 @@ public int highlight_error(file_t *file, const char *start, const char *end, con
int col = 0;
for (const char *sp = line; *sp && *sp != '\n'; ++sp) {
char print_char;
- if (sp < start)
- print_char = ' ';
- else if (sp == start && sp == end)
- print_char = '^';
- else if (sp >= start && sp < end)
- print_char = '-';
- else
- print_char = ' ';
+ if (sp < start) print_char = ' ';
+ else if (sp == start && sp == end) print_char = '^';
+ else if (sp >= start && sp < end) print_char = '-';
+ else print_char = ' ';
printed += fputc_column(stderr, *sp, print_char, &col);
}
printed += fputs("\n", stderr);
diff --git a/src/stdlib/files.h b/src/stdlib/files.h
index f650f78e..d3e5ebe8 100644
--- a/src/stdlib/files.h
+++ b/src/stdlib/files.h
@@ -16,20 +16,14 @@ typedef struct {
} file_t;
char *resolve_path(const char *path, const char *relative_to, const char *system_path);
-__attribute__((pure, nonnull))
-char *file_base_name(const char *path);
-__attribute__((nonnull))
-file_t *load_file(const char *filename);
-__attribute__((nonnull, returns_nonnull))
-file_t *spoof_file(const char *filename, const char *text);
-__attribute__((pure, nonnull))
-int64_t get_line_number(file_t *f, const char *p);
-__attribute__((pure, nonnull))
-int64_t get_line_column(file_t *f, const char *p);
-__attribute__((pure, nonnull))
-const char *get_line(file_t *f, int64_t line_number);
-__attribute__((pure, nonnull))
-const char *get_file_pos(file_t *f, const char *p);
-int highlight_error(file_t *file, const char *start, const char *end, const char *hl_color, int64_t context_lines, bool use_color);
+__attribute__((pure, nonnull)) char *file_base_name(const char *path);
+__attribute__((nonnull)) file_t *load_file(const char *filename);
+__attribute__((nonnull, returns_nonnull)) file_t *spoof_file(const char *filename, const char *text);
+__attribute__((pure, nonnull)) int64_t get_line_number(file_t *f, const char *p);
+__attribute__((pure, nonnull)) int64_t get_line_column(file_t *f, const char *p);
+__attribute__((pure, nonnull)) const char *get_line(file_t *f, int64_t line_number);
+__attribute__((pure, nonnull)) const char *get_file_pos(file_t *f, const char *p);
+int highlight_error(file_t *file, const char *start, const char *end, const char *hl_color, int64_t context_lines,
+ bool use_color);
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/stdlib/fpconv.c b/src/stdlib/fpconv.c
index 97699784..8b994cfa 100644
--- a/src/stdlib/fpconv.c
+++ b/src/stdlib/fpconv.c
@@ -6,37 +6,46 @@
#include "fpconv.h"
#include "powers.h"
-#define fracmask 0x000FFFFFFFFFFFFFU
-#define expmask 0x7FF0000000000000U
+#define fracmask 0x000FFFFFFFFFFFFFU
+#define expmask 0x7FF0000000000000U
#define hiddenbit 0x0010000000000000U
-#define signmask 0x8000000000000000U
-#define expbias (1023 + 52)
+#define signmask 0x8000000000000000U
+#define expbias (1023 + 52)
#define absv(n) ((n) < 0 ? -(n) : (n))
#define minv(a, b) ((a) < (b) ? (a) : (b))
-static uint64_t tens[] = {
- 10000000000000000000U, 1000000000000000000U, 100000000000000000U,
- 10000000000000000U, 1000000000000000U, 100000000000000U,
- 10000000000000U, 1000000000000U, 100000000000U,
- 10000000000U, 1000000000U, 100000000U,
- 10000000U, 1000000U, 100000U,
- 10000U, 1000U, 100U,
- 10U, 1U
-};
-
-static inline uint64_t get_dbits(double d)
-{
+static uint64_t tens[] = {10000000000000000000U,
+ 1000000000000000000U,
+ 100000000000000000U,
+ 10000000000000000U,
+ 1000000000000000U,
+ 100000000000000U,
+ 10000000000000U,
+ 1000000000000U,
+ 100000000000U,
+ 10000000000U,
+ 1000000000U,
+ 100000000U,
+ 10000000U,
+ 1000000U,
+ 100000U,
+ 10000U,
+ 1000U,
+ 100U,
+ 10U,
+ 1U};
+
+static inline uint64_t get_dbits(double d) {
union {
- double dbl;
+ double dbl;
uint64_t i;
- } dbl_bits = { d };
+ } dbl_bits = {d};
return dbl_bits.i;
}
-static Fp build_fp(double d)
-{
+static Fp build_fp(double d) {
uint64_t bits = get_dbits(d);
Fp fp;
@@ -54,8 +63,7 @@ static Fp build_fp(double d)
return fp;
}
-static void normalize(Fp* fp)
-{
+static void normalize(Fp *fp) {
while ((fp->frac & hiddenbit) == 0) {
fp->frac <<= 1;
fp->exp--;
@@ -66,10 +74,9 @@ static void normalize(Fp* fp)
fp->exp -= shift;
}
-static void get_normalized_boundaries(Fp* fp, Fp* lower, Fp* upper)
-{
+static void get_normalized_boundaries(Fp *fp, Fp *lower, Fp *upper) {
upper->frac = (fp->frac << 1) + 1;
- upper->exp = fp->exp - 1;
+ upper->exp = fp->exp - 1;
while ((upper->frac & (hiddenbit << 1)) == 0) {
upper->frac <<= 1;
@@ -81,64 +88,55 @@ static void get_normalized_boundaries(Fp* fp, Fp* lower, Fp* upper)
upper->frac <<= u_shift;
upper->exp = upper->exp - u_shift;
-
int l_shift = fp->frac == hiddenbit ? 2 : 1;
lower->frac = (fp->frac << l_shift) - 1;
lower->exp = fp->exp - l_shift;
-
lower->frac <<= lower->exp - upper->exp;
lower->exp = upper->exp;
}
-static Fp multiply(Fp* a, Fp* b)
-{
+static Fp multiply(Fp *a, Fp *b) {
const uint64_t lomask = 0x00000000FFFFFFFF;
- uint64_t ah_bl = (a->frac >> 32) * (b->frac & lomask);
+ uint64_t ah_bl = (a->frac >> 32) * (b->frac & lomask);
uint64_t al_bh = (a->frac & lomask) * (b->frac >> 32);
uint64_t al_bl = (a->frac & lomask) * (b->frac & lomask);
- uint64_t ah_bh = (a->frac >> 32) * (b->frac >> 32);
+ uint64_t ah_bh = (a->frac >> 32) * (b->frac >> 32);
uint64_t tmp = (ah_bl & lomask) + (al_bh & lomask) + (al_bl >> 32);
/* round up */
tmp += 1U << 31;
- Fp fp = {
- ah_bh + (ah_bl >> 32) + (al_bh >> 32) + (tmp >> 32),
- a->exp + b->exp + 64
- };
+ Fp fp = {ah_bh + (ah_bl >> 32) + (al_bh >> 32) + (tmp >> 32), a->exp + b->exp + 64};
return fp;
}
-static void round_digit(char* digits, int ndigits, uint64_t delta, uint64_t rem, uint64_t kappa, uint64_t frac)
-{
- while (rem < frac && delta - rem >= kappa &&
- (rem + kappa < frac || frac - rem > rem + kappa - frac)) {
+static void round_digit(char *digits, int ndigits, uint64_t delta, uint64_t rem, uint64_t kappa, uint64_t frac) {
+ while (rem < frac && delta - rem >= kappa && (rem + kappa < frac || frac - rem > rem + kappa - frac)) {
digits[ndigits - 1]--;
rem += kappa;
}
}
-static int generate_digits(Fp* fp, Fp* upper, Fp* lower, char* digits, int* K)
-{
+static int generate_digits(Fp *fp, Fp *upper, Fp *lower, char *digits, int *K) {
uint64_t wfrac = upper->frac - fp->frac;
uint64_t delta = upper->frac - lower->frac;
Fp one;
one.frac = 1ULL << -upper->exp;
- one.exp = upper->exp;
+ one.exp = upper->exp;
uint64_t part1 = upper->frac >> -one.exp;
uint64_t part2 = upper->frac & (one.frac - 1);
int idx = 0, kappa = 10;
- uint64_t* divp;
+ uint64_t *divp;
/* 1000000000 */
- for(divp = tens + 10; kappa > 0; divp++) {
+ for (divp = tens + 10; kappa > 0; divp++) {
uint64_t div = *divp;
unsigned digit = part1 / div;
@@ -150,7 +148,7 @@ static int generate_digits(Fp* fp, Fp* upper, Fp* lower, char* digits, int* K)
part1 -= digit * div;
kappa--;
- uint64_t tmp = (part1 <<-one.exp) + part2;
+ uint64_t tmp = (part1 << -one.exp) + part2;
if (tmp <= delta) {
*K += kappa;
round_digit(digits, idx, delta, tmp, div << -one.exp, wfrac);
@@ -160,7 +158,7 @@ static int generate_digits(Fp* fp, Fp* upper, Fp* lower, char* digits, int* K)
}
/* 10 */
- uint64_t* unit = tens + 18;
+ uint64_t *unit = tens + 18;
while (true) {
part2 *= 10;
@@ -184,8 +182,7 @@ static int generate_digits(Fp* fp, Fp* upper, Fp* lower, char* digits, int* K)
}
}
-static int grisu2(double d, char* digits, int* K)
-{
+static int grisu2(double d, char *digits, int *K) {
Fp w = build_fp(d);
Fp lower, upper;
@@ -196,7 +193,7 @@ static int grisu2(double d, char* digits, int* K)
int k;
Fp cp = find_cachedpow10(upper.exp, &k);
- w = multiply(&w, &cp);
+ w = multiply(&w, &cp);
upper = multiply(&upper, &cp);
lower = multiply(&lower, &cp);
@@ -208,8 +205,7 @@ static int grisu2(double d, char* digits, int* K)
return generate_digits(&w, &upper, &lower, digits, K);
}
-static int emit_digits(char* digits, int ndigits, char* dest, int K, bool neg)
-{
+static int emit_digits(char *digits, int ndigits, char *dest, int K, bool neg) {
int exp = absv(K + ndigits - 1);
int max_trailing_zeros = 7;
@@ -240,7 +236,7 @@ static int emit_digits(char* digits, int ndigits, char* dest, int K, bool neg)
return ndigits + 2 + offset;
- /* fp > 1.0 */
+ /* fp > 1.0 */
} else {
memcpy(dest, digits, (size_t)offset);
dest[offset] = '.';
@@ -288,8 +284,7 @@ static int emit_digits(char* digits, int ndigits, char* dest, int K, bool neg)
return idx;
}
-static int filter_special(double fp, char* dest)
-{
+static int filter_special(double fp, char *dest) {
if (fp == 0.0) {
dest[0] = '0';
return 1;
@@ -304,17 +299,20 @@ static int filter_special(double fp, char* dest)
}
if (bits & fracmask) {
- dest[0] = 'n'; dest[1] = 'a'; dest[2] = 'n';
+ dest[0] = 'n';
+ dest[1] = 'a';
+ dest[2] = 'n';
} else {
- dest[0] = 'i'; dest[1] = 'n'; dest[2] = 'f';
+ dest[0] = 'i';
+ dest[1] = 'n';
+ dest[2] = 'f';
}
return 3;
}
-int fpconv_dtoa(double d, char dest[24])
-{
+int fpconv_dtoa(double d, char dest[24]) {
char digits[18];
int str_len = 0;
diff --git a/src/stdlib/functiontype.c b/src/stdlib/functiontype.c
index 6d692c6d..a6e12798 100644
--- a/src/stdlib/functiontype.c
+++ b/src/stdlib/functiontype.c
@@ -9,18 +9,17 @@
#include "types.h"
#include "util.h"
-public Text_t Func$as_text(const void *fn, bool colorize, const TypeInfo_t *type)
-{
+public
+Text_t Func$as_text(const void *fn, bool colorize, const TypeInfo_t *type) {
Text_t text = Text$from_str(type->FunctionInfo.type_str);
- if (fn && colorize)
- text = Text$concat(Text("\x1b[32;1m"), text, Text("\x1b[m"));
+ if (fn && colorize) text = Text$concat(Text("\x1b[32;1m"), text, Text("\x1b[m"));
return text;
}
-public PUREFUNC bool Func$is_none(const void *obj, const TypeInfo_t *info)
-{
+public
+PUREFUNC bool Func$is_none(const void *obj, const TypeInfo_t *info) {
(void)info;
- return *(void**)obj == NULL;
+ return *(void **)obj == NULL;
}
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/stdlib/functiontype.h b/src/stdlib/functiontype.h
index 095d630e..3169cfc9 100644
--- a/src/stdlib/functiontype.h
+++ b/src/stdlib/functiontype.h
@@ -13,20 +13,27 @@ OptionalText_t get_function_name(void *fn);
OptionalText_t get_function_filename(void *fn);
int64_t get_function_line_num(void *fn);
Text_t Func$as_text(const void *fn, bool colorize, const TypeInfo_t *type);
-PUREFUNC bool Func$is_none(const void *obj, const TypeInfo_t*);
+PUREFUNC bool Func$is_none(const void *obj, const TypeInfo_t *);
-#define Func$metamethods { \
- .as_text=Func$as_text, \
- .is_none=Func$is_none, \
- .serialize=cannot_serialize, \
- .deserialize=cannot_deserialize, \
-}
+#define Func$metamethods \
+ { \
+ .as_text = Func$as_text, \
+ .is_none = Func$is_none, \
+ .serialize = cannot_serialize, \
+ .deserialize = cannot_deserialize, \
+ }
-#define Function$info(typestr) &((TypeInfo_t){.size=sizeof(void*), .align=__alignof__(void*), \
- .tag=FunctionInfo, .FunctionInfo.type_str=typestr, \
- .metamethods=Func$metamethods})
-#define Closure$info(typestr) &((TypeInfo_t){.size=sizeof(void*[2]), .align=__alignof__(void*), \
- .tag=FunctionInfo, .FunctionInfo.type_str=typestr, \
- .metamethods=Func$metamethods})
+#define Function$info(typestr) \
+ &((TypeInfo_t){.size = sizeof(void *), \
+ .align = __alignof__(void *), \
+ .tag = FunctionInfo, \
+ .FunctionInfo.type_str = typestr, \
+ .metamethods = Func$metamethods})
+#define Closure$info(typestr) \
+ &((TypeInfo_t){.size = sizeof(void *[2]), \
+ .align = __alignof__(void *), \
+ .tag = FunctionInfo, \
+ .FunctionInfo.type_str = typestr, \
+ .metamethods = Func$metamethods})
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/stdlib/integers.c b/src/stdlib/integers.c
index e24d984d..93095a70 100644
--- a/src/stdlib/integers.c
+++ b/src/stdlib/integers.c
@@ -17,20 +17,19 @@
#include "text.h"
#include "types.h"
-public int Int$print(FILE *f, Int_t i) {
+public
+int Int$print(FILE *f, Int_t i) {
if (likely(i.small & 1L)) {
- return _print_int(f, (int64_t)((i.small)>>2L));
+ return _print_int(f, (int64_t)((i.small) >> 2L));
} else {
return gmp_fprintf(f, "%Zd", *i.big);
}
}
-static inline Text_t _int64_to_text(int64_t n)
-{
- if (n == INT64_MIN)
- return Text("-9223372036854775808");
+static inline Text_t _int64_to_text(int64_t n) {
+ if (n == INT64_MIN) return Text("-9223372036854775808");
- char buf[21] = {[20]=0}; // Big enough for INT64_MIN + '\0'
+ char buf[21] = {[20] = 0}; // Big enough for INT64_MIN + '\0'
char *p = &buf[19];
bool negative = n < 0;
if (negative) n = -n; // Safe to do because we checked for INT64_MIN earlier
@@ -40,13 +39,13 @@ static inline Text_t _int64_to_text(int64_t n)
n /= 10;
} while (n > 0);
- if (negative)
- *(p--) = '-';
+ if (negative) *(p--) = '-';
return Text$from_strn(p + 1, (size_t)(&buf[19] - p));
}
-public Text_t Int$value_as_text(Int_t i) {
+public
+Text_t Int$value_as_text(Int_t i) {
if (likely(i.small & 1L)) {
return _int64_to_text(i.small >> 2L);
} else {
@@ -55,74 +54,76 @@ public Text_t Int$value_as_text(Int_t i) {
}
}
-public Text_t Int$as_text(const void *i, bool colorize, const TypeInfo_t *info) {
+public
+Text_t Int$as_text(const void *i, bool colorize, const TypeInfo_t *info) {
(void)info;
if (!i) return Text("Int");
- Text_t text = Int$value_as_text(*(Int_t*)i);
+ Text_t text = Int$value_as_text(*(Int_t *)i);
if (colorize) text = Text$concat(Text("\x1b[35m"), text, Text("\x1b[m"));
return text;
}
-static bool Int$is_none(const void *i, const TypeInfo_t *info)
-{
+static bool Int$is_none(const void *i, const TypeInfo_t *info) {
(void)info;
- return ((Int_t*)i)->small == 0L;
+ return ((Int_t *)i)->small == 0L;
}
-public PUREFUNC int32_t Int$compare_value(const Int_t x, const Int_t y) {
- if (likely(x.small & y.small & 1L))
- return (x.small > y.small) - (x.small < y.small);
- else if (x.small & 1)
- return -mpz_cmp_si(*y.big, x.small);
- else if (y.small & 1)
- return mpz_cmp_si(*x.big, y.small);
- else
- return x.big == y.big ? 0 : mpz_cmp(*x.big, *y.big);
+public
+PUREFUNC int32_t Int$compare_value(const Int_t x, const Int_t y) {
+ if (likely(x.small & y.small & 1L)) return (x.small > y.small) - (x.small < y.small);
+ else if (x.small & 1) return -mpz_cmp_si(*y.big, x.small);
+ else if (y.small & 1) return mpz_cmp_si(*x.big, y.small);
+ else return x.big == y.big ? 0 : mpz_cmp(*x.big, *y.big);
}
-public PUREFUNC int32_t Int$compare(const void *x, const void *y, const TypeInfo_t *info) {
+public
+PUREFUNC int32_t Int$compare(const void *x, const void *y, const TypeInfo_t *info) {
(void)info;
- return Int$compare_value(*(Int_t*)x, *(Int_t*)y);
+ return Int$compare_value(*(Int_t *)x, *(Int_t *)y);
}
-public PUREFUNC bool Int$equal_value(const Int_t x, const Int_t y) {
- if (likely((x.small | y.small) & 1L))
- return x.small == y.small;
- else
- return x.big == y.big ? 0 : (mpz_cmp(*x.big, *y.big) == 0);
+public
+PUREFUNC bool Int$equal_value(const Int_t x, const Int_t y) {
+ if (likely((x.small | y.small) & 1L)) return x.small == y.small;
+ else return x.big == y.big ? 0 : (mpz_cmp(*x.big, *y.big) == 0);
}
-public PUREFUNC bool Int$equal(const void *x, const void *y, const TypeInfo_t *info) {
+public
+PUREFUNC bool Int$equal(const void *x, const void *y, const TypeInfo_t *info) {
(void)info;
- return Int$equal_value(*(Int_t*)x, *(Int_t*)y);
+ return Int$equal_value(*(Int_t *)x, *(Int_t *)y);
}
-public CONSTFUNC Int_t Int$clamped(Int_t x, Int_t low, Int_t high) {
+public
+CONSTFUNC Int_t Int$clamped(Int_t x, Int_t low, Int_t high) {
return (Int$compare(&x, &low, &Int$info) <= 0) ? low : (Int$compare(&x, &high, &Int$info) >= 0 ? high : x);
}
-public CONSTFUNC bool Int$is_between(const Int_t x, const Int_t low, const Int_t high) {
+public
+CONSTFUNC bool Int$is_between(const Int_t x, const Int_t low, const Int_t high) {
return Int$compare_value(low, x) <= 0 && Int$compare_value(x, high) <= 0;
}
-public PUREFUNC uint64_t Int$hash(const void *vx, const TypeInfo_t *info) {
+public
+PUREFUNC uint64_t Int$hash(const void *vx, const TypeInfo_t *info) {
(void)info;
- Int_t *x = (Int_t*)vx;
+ Int_t *x = (Int_t *)vx;
if (likely(x->small & 1L)) {
- return siphash24((void*)x, sizeof(Int_t));
+ return siphash24((void *)x, sizeof(Int_t));
} else {
char *str = mpz_get_str(NULL, 16, *x->big);
- return siphash24((void*)str, strlen(str));
+ return siphash24((void *)str, strlen(str));
}
}
-public Text_t Int$hex(Int_t i, Int_t digits_int, bool uppercase, bool prefix) {
- if (Int$is_negative(i))
- return Text$concat(Text("-"), Int$hex(Int$negative(i), digits_int, uppercase, prefix));
+public
+Text_t Int$hex(Int_t i, Int_t digits_int, bool uppercase, bool prefix) {
+ if (Int$is_negative(i)) return Text$concat(Text("-"), Int$hex(Int$negative(i), digits_int, uppercase, prefix));
if (likely(i.small & 1L)) {
uint64_t u64 = (uint64_t)(i.small >> 2);
- return Text$from_str(String(hex(u64, .no_prefix=!prefix, .digits=Int32$from_int(digits_int, false), .uppercase=uppercase)));
+ return Text$from_str(String(
+ hex(u64, .no_prefix = !prefix, .digits = Int32$from_int(digits_int, false), .uppercase = uppercase)));
} else {
char *str = mpz_get_str(NULL, 16, *i.big);
if (uppercase) {
@@ -131,97 +132,88 @@ public Text_t Int$hex(Int_t i, Int_t digits_int, bool uppercase, bool prefix) {
}
int64_t digits = Int64$from_int(digits_int, false);
int64_t needed_zeroes = digits - (int64_t)strlen(str);
- if (needed_zeroes <= 0)
- return prefix ? Text$concat(Text("0x"), Text$from_str(str)) : Text$from_str(str);
+ if (needed_zeroes <= 0) return prefix ? Text$concat(Text("0x"), Text$from_str(str)) : Text$from_str(str);
char *zeroes = GC_MALLOC_ATOMIC((size_t)(needed_zeroes));
memset(zeroes, '0', (size_t)(needed_zeroes));
- if (prefix)
- return Text$concat(Text("0x"), Text$from_str(zeroes), Text$from_str(str));
- else
- return Text$concat(Text$from_str(zeroes), Text$from_str(str));
+ if (prefix) return Text$concat(Text("0x"), Text$from_str(zeroes), Text$from_str(str));
+ else return Text$concat(Text$from_str(zeroes), Text$from_str(str));
}
}
-public Text_t Int$octal(Int_t i, Int_t digits_int, bool prefix) {
- if (Int$is_negative(i))
- return Text$concat(Text("-"), Int$octal(Int$negative(i), digits_int, prefix));
+public
+Text_t Int$octal(Int_t i, Int_t digits_int, bool prefix) {
+ if (Int$is_negative(i)) return Text$concat(Text("-"), Int$octal(Int$negative(i), digits_int, prefix));
if (likely(i.small & 1L)) {
uint64_t u64 = (uint64_t)(i.small >> 2);
- return Text$from_str(String(oct(u64, .no_prefix=!prefix, .digits=Int32$from_int(digits_int, false))));
+ return Text$from_str(String(oct(u64, .no_prefix = !prefix, .digits = Int32$from_int(digits_int, false))));
} else {
int64_t digits = Int64$from_int(digits_int, false);
char *str = mpz_get_str(NULL, 8, *i.big);
int64_t needed_zeroes = digits - (int64_t)strlen(str);
- if (needed_zeroes <= 0)
- return prefix ? Text$concat(Text("0o"), Text$from_str(str)) : Text$from_str(str);
+ if (needed_zeroes <= 0) return prefix ? Text$concat(Text("0o"), Text$from_str(str)) : Text$from_str(str);
char *zeroes = GC_MALLOC_ATOMIC((size_t)(needed_zeroes));
memset(zeroes, '0', (size_t)(needed_zeroes));
- if (prefix)
- return Text$concat(Text("0o"), Text$from_str(zeroes), Text$from_str(str));
- else
- return Text$concat(Text$from_str(zeroes), Text$from_str(str));
+ if (prefix) return Text$concat(Text("0o"), Text$from_str(zeroes), Text$from_str(str));
+ else return Text$concat(Text$from_str(zeroes), Text$from_str(str));
}
}
-public Int_t Int$slow_plus(Int_t x, Int_t y) {
+public
+Int_t Int$slow_plus(Int_t x, Int_t y) {
mpz_t result;
mpz_init_set_int(result, x);
if (y.small & 1L) {
- if (y.small < 0L)
- mpz_sub_ui(result, result, (uint64_t)(-(y.small >> 2L)));
- else
- mpz_add_ui(result, result, (uint64_t)(y.small >> 2L));
+ if (y.small < 0L) mpz_sub_ui(result, result, (uint64_t)(-(y.small >> 2L)));
+ else mpz_add_ui(result, result, (uint64_t)(y.small >> 2L));
} else {
mpz_add(result, result, *y.big);
}
return Int$from_mpz(result);
}
-public Int_t Int$slow_minus(Int_t x, Int_t y) {
+public
+Int_t Int$slow_minus(Int_t x, Int_t y) {
mpz_t result;
mpz_init_set_int(result, x);
if (y.small & 1L) {
- if (y.small < 0L)
- mpz_add_ui(result, result, (uint64_t)(-(y.small >> 2L)));
- else
- mpz_sub_ui(result, result, (uint64_t)(y.small >> 2L));
+ if (y.small < 0L) mpz_add_ui(result, result, (uint64_t)(-(y.small >> 2L)));
+ else mpz_sub_ui(result, result, (uint64_t)(y.small >> 2L));
} else {
mpz_sub(result, result, *y.big);
}
return Int$from_mpz(result);
}
-public Int_t Int$slow_times(Int_t x, Int_t y) {
+public
+Int_t Int$slow_times(Int_t x, Int_t y) {
mpz_t result;
mpz_init_set_int(result, x);
- if (y.small & 1L)
- mpz_mul_si(result, result, y.small >> 2L);
- else
- mpz_mul(result, result, *y.big);
+ if (y.small & 1L) mpz_mul_si(result, result, y.small >> 2L);
+ else mpz_mul(result, result, *y.big);
return Int$from_mpz(result);
}
-public Int_t Int$slow_divided_by(Int_t dividend, Int_t divisor) {
- // Euclidean division, see: https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf
+public
+Int_t Int$slow_divided_by(Int_t dividend, Int_t divisor) {
+ // Euclidean division, see:
+ // https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf
mpz_t quotient, remainder;
mpz_init_set_int(quotient, dividend);
mpz_init_set_int(remainder, divisor);
mpz_tdiv_qr(quotient, remainder, quotient, remainder);
if (mpz_sgn(remainder) < 0) {
bool d_positive = likely(divisor.small & 1L) ? divisor.small > 0x1L : mpz_sgn(*divisor.big) > 0;
- if (d_positive)
- mpz_sub_ui(quotient, quotient, 1);
- else
- mpz_add_ui(quotient, quotient, 1);
+ if (d_positive) mpz_sub_ui(quotient, quotient, 1);
+ else mpz_add_ui(quotient, quotient, 1);
}
return Int$from_mpz(quotient);
}
-public Int_t Int$slow_modulo(Int_t x, Int_t modulus)
-{
+public
+Int_t Int$slow_modulo(Int_t x, Int_t modulus) {
mpz_t result;
mpz_init_set_int(result, x);
mpz_t divisor;
@@ -230,8 +222,8 @@ public Int_t Int$slow_modulo(Int_t x, Int_t modulus)
return Int$from_mpz(result);
}
-public Int_t Int$slow_modulo1(Int_t x, Int_t modulus)
-{
+public
+Int_t Int$slow_modulo1(Int_t x, Int_t modulus) {
mpz_t result;
mpz_init_set_int(result, x);
mpz_sub_ui(result, result, 1);
@@ -242,8 +234,8 @@ public Int_t Int$slow_modulo1(Int_t x, Int_t modulus)
return Int$from_mpz(result);
}
-public Int_t Int$slow_left_shifted(Int_t x, Int_t y)
-{
+public
+Int_t Int$slow_left_shifted(Int_t x, Int_t y) {
mp_bitcnt_t bits = (mp_bitcnt_t)Int64$from_int(y, false);
mpz_t result;
mpz_init_set_int(result, x);
@@ -251,8 +243,8 @@ public Int_t Int$slow_left_shifted(Int_t x, Int_t y)
return Int$from_mpz(result);
}
-public Int_t Int$slow_right_shifted(Int_t x, Int_t y)
-{
+public
+Int_t Int$slow_right_shifted(Int_t x, Int_t y) {
mp_bitcnt_t bits = (mp_bitcnt_t)Int64$from_int(y, false);
mpz_t result;
mpz_init_set_int(result, x);
@@ -260,8 +252,8 @@ public Int_t Int$slow_right_shifted(Int_t x, Int_t y)
return Int$from_mpz(result);
}
-public Int_t Int$slow_bit_and(Int_t x, Int_t y)
-{
+public
+Int_t Int$slow_bit_and(Int_t x, Int_t y) {
mpz_t result;
mpz_init_set_int(result, x);
mpz_t y_mpz;
@@ -270,8 +262,8 @@ public Int_t Int$slow_bit_and(Int_t x, Int_t y)
return Int$from_mpz(result);
}
-public Int_t Int$slow_bit_or(Int_t x, Int_t y)
-{
+public
+Int_t Int$slow_bit_or(Int_t x, Int_t y) {
mpz_t result;
mpz_init_set_int(result, x);
mpz_t y_mpz;
@@ -280,8 +272,8 @@ public Int_t Int$slow_bit_or(Int_t x, Int_t y)
return Int$from_mpz(result);
}
-public Int_t Int$slow_bit_xor(Int_t x, Int_t y)
-{
+public
+Int_t Int$slow_bit_xor(Int_t x, Int_t y) {
mpz_t result;
mpz_init_set_int(result, x);
mpz_t y_mpz;
@@ -290,8 +282,8 @@ public Int_t Int$slow_bit_xor(Int_t x, Int_t y)
return Int$from_mpz(result);
}
-public Int_t Int$slow_negated(Int_t x)
-{
+public
+Int_t Int$slow_negated(Int_t x) {
mpz_t result;
mpz_init_set_int(result, x);
mpz_neg(result, result);
@@ -299,10 +291,9 @@ public Int_t Int$slow_negated(Int_t x)
return Int$from_mpz(result);
}
-public Int_t Int$slow_negative(Int_t x)
-{
- if (likely(x.small & 1L))
- return (Int_t){.small=4L*-((x.small)>>2L) + 1L};
+public
+Int_t Int$slow_negative(Int_t x) {
+ if (likely(x.small & 1L)) return (Int_t){.small = 4L * -((x.small) >> 2L) + 1L};
mpz_t result;
mpz_init_set_int(result, x);
@@ -310,10 +301,9 @@ public Int_t Int$slow_negative(Int_t x)
return Int$from_mpz(result);
}
-public Int_t Int$abs(Int_t x)
-{
- if (likely(x.small & 1L))
- return (Int_t){.small=4L*labs((x.small)>>2L) + 1L};
+public
+Int_t Int$abs(Int_t x) {
+ if (likely(x.small & 1L)) return (Int_t){.small = 4L * labs((x.small) >> 2L) + 1L};
mpz_t result;
mpz_init_set_int(result, x);
@@ -321,53 +311,45 @@ public Int_t Int$abs(Int_t x)
return Int$from_mpz(result);
}
-public Int_t Int$power(Int_t base, Int_t exponent)
-{
+public
+Int_t Int$power(Int_t base, Int_t exponent) {
int64_t exp = Int64$from_int(exponent, false);
- if (unlikely(exp < 0))
- fail("Cannot take a negative power of an integer!");
+ if (unlikely(exp < 0)) fail("Cannot take a negative power of an integer!");
mpz_t result;
mpz_init_set_int(result, base);
mpz_pow_ui(result, result, (uint64_t)exp);
return Int$from_mpz(result);
}
-public Int_t Int$gcd(Int_t x, Int_t y)
-{
- if (likely(x.small & y.small & 0x1L))
- return I_small(Int32$gcd(x.small >> 2L, y.small >> 2L));
+public
+Int_t Int$gcd(Int_t x, Int_t y) {
+ if (likely(x.small & y.small & 0x1L)) return I_small(Int32$gcd(x.small >> 2L, y.small >> 2L));
mpz_t result;
mpz_init(result);
- if (x.small & 0x1L)
- mpz_gcd_ui(result, *y.big, (uint64_t)labs(x.small>>2L));
- else if (y.small & 0x1L)
- mpz_gcd_ui(result, *x.big, (uint64_t)labs(y.small>>2L));
- else
- mpz_gcd(result, *x.big, *y.big);
+ if (x.small & 0x1L) mpz_gcd_ui(result, *y.big, (uint64_t)labs(x.small >> 2L));
+ else if (y.small & 0x1L) mpz_gcd_ui(result, *x.big, (uint64_t)labs(y.small >> 2L));
+ else mpz_gcd(result, *x.big, *y.big);
return Int$from_mpz(result);
}
-public OptionalInt_t Int$sqrt(Int_t i)
-{
- if (Int$compare_value(i, I(0)) < 0)
- return NONE_INT;
+public
+OptionalInt_t Int$sqrt(Int_t i) {
+ if (Int$compare_value(i, I(0)) < 0) return NONE_INT;
mpz_t result;
mpz_init_set_int(result, i);
mpz_sqrt(result, result);
return Int$from_mpz(result);
}
-public bool Int$get_bit(Int_t x, Int_t bit_index)
-{
+public
+bool Int$get_bit(Int_t x, Int_t bit_index) {
mpz_t i;
mpz_init_set_int(i, x);
- if (Int$compare_value(bit_index, I(1)) < 0)
- fail("Invalid bit index (expected 1 or higher): ", bit_index);
- if (Int$compare_value(bit_index, Int$from_int64(INT64_MAX)) > 0)
- fail("Bit index is too large! ", bit_index);
+ if (Int$compare_value(bit_index, I(1)) < 0) fail("Invalid bit index (expected 1 or higher): ", bit_index);
+ if (Int$compare_value(bit_index, Int$from_int64(INT64_MAX)) > 0) fail("Bit index is too large! ", bit_index);
- int is_bit_set = mpz_tstbit(i, (mp_bitcnt_t)(Int64$from_int(bit_index, true)-1));
+ int is_bit_set = mpz_tstbit(i, (mp_bitcnt_t)(Int64$from_int(bit_index, true) - 1));
return (bool)is_bit_set;
}
@@ -376,37 +358,41 @@ typedef struct {
Int_t step;
} IntRange_t;
-static OptionalInt_t _next_int(IntRange_t *info)
-{
+static OptionalInt_t _next_int(IntRange_t *info) {
OptionalInt_t i = info->current;
if (!Int$is_none(&i, &Int$info)) {
Int_t next = Int$plus(i, info->step);
- if (!Int$is_none(&info->last, &Int$info) && Int$compare_value(next, info->last) == Int$compare_value(info->step, I(0)))
+ if (!Int$is_none(&info->last, &Int$info)
+ && Int$compare_value(next, info->last) == Int$compare_value(info->step, I(0)))
next = NONE_INT;
info->current = next;
}
return i;
}
-public PUREFUNC Closure_t Int$to(Int_t first, Int_t last, OptionalInt_t step) {
+public
+PUREFUNC Closure_t Int$to(Int_t first, Int_t last, OptionalInt_t step) {
IntRange_t *range = GC_MALLOC(sizeof(IntRange_t));
range->current = first;
range->last = last;
- range->step = Int$is_none(&step, &Int$info) ?
- Int$compare_value(last, first) >= 0 ? (Int_t){.small=(1L<<2L)|1L} : (Int_t){.small=(-1L>>2L)|1L}
- : step;
- return (Closure_t){.fn=_next_int, .userdata=range};
+ range->step = Int$is_none(&step, &Int$info) ? Int$compare_value(last, first) >= 0
+ ? (Int_t){.small = (1L << 2L) | 1L}
+ : (Int_t){.small = (-1L >> 2L) | 1L}
+ : step;
+ return (Closure_t){.fn = _next_int, .userdata = range};
}
-public PUREFUNC Closure_t Int$onward(Int_t first, Int_t step) {
+public
+PUREFUNC Closure_t Int$onward(Int_t first, Int_t step) {
IntRange_t *range = GC_MALLOC(sizeof(IntRange_t));
range->current = first;
range->last = NONE_INT;
range->step = step;
- return (Closure_t){.fn=_next_int, .userdata=range};
+ return (Closure_t){.fn = _next_int, .userdata = range};
}
-public Int_t Int$from_str(const char *str) {
+public
+Int_t Int$from_str(const char *str) {
mpz_t i;
int result;
if (strncmp(str, "0x", 2) == 0) {
@@ -418,12 +404,12 @@ public Int_t Int$from_str(const char *str) {
} else {
result = mpz_init_set_str(i, str, 10);
}
- if (result != 0)
- return NONE_INT;
+ if (result != 0) return NONE_INT;
return Int$from_mpz(i);
}
-public OptionalInt_t Int$parse(Text_t text, Text_t *remainder) {
+public
+OptionalInt_t Int$parse(Text_t text, Text_t *remainder) {
const char *str = Text$as_c_string(text);
mpz_t i;
int result;
@@ -455,8 +441,8 @@ public OptionalInt_t Int$parse(Text_t text, Text_t *remainder) {
return Int$from_mpz(i);
}
-public bool Int$is_prime(Int_t x, Int_t reps)
-{
+public
+bool Int$is_prime(Int_t x, Int_t reps) {
mpz_t p;
mpz_init_set_int(p, x);
if (unlikely(Int$compare_value(reps, I(9999)) > 0))
@@ -465,8 +451,8 @@ public bool Int$is_prime(Int_t x, Int_t reps)
return (mpz_probab_prime_p(p, reps_int) != 0);
}
-public Int_t Int$next_prime(Int_t x)
-{
+public
+Int_t Int$next_prime(Int_t x) {
mpz_t p;
mpz_init_set_int(p, x);
mpz_nextprime(p, p);
@@ -475,28 +461,25 @@ public Int_t Int$next_prime(Int_t x)
#if __GNU_MP_VERSION >= 6
#if __GNU_MP_VERSION_MINOR >= 3
-public OptionalInt_t Int$prev_prime(Int_t x)
-{
+public
+OptionalInt_t Int$prev_prime(Int_t x) {
mpz_t p;
mpz_init_set_int(p, x);
- if (unlikely(mpz_prevprime(p, p) == 0))
- return NONE_INT;
+ if (unlikely(mpz_prevprime(p, p) == 0)) return NONE_INT;
return Int$from_mpz(p);
}
#endif
#endif
-public Int_t Int$choose(Int_t n, Int_t k)
-{
- if unlikely (Int$compare_value(n, I_small(0)) < 0)
- fail("Negative inputs are not supported for choose()");
+public
+Int_t Int$choose(Int_t n, Int_t k) {
+ if unlikely (Int$compare_value(n, I_small(0)) < 0) fail("Negative inputs are not supported for choose()");
mpz_t ret;
mpz_init(ret);
int64_t k_i64 = Int64$from_int(k, false);
- if unlikely (k_i64 < 0)
- fail("Negative inputs are not supported for choose()");
+ if unlikely (k_i64 < 0) fail("Negative inputs are not supported for choose()");
if likely (n.small & 1L) {
mpz_bin_uiui(ret, (unsigned long)(n.small >> 2L), (unsigned long)k_i64);
@@ -508,21 +491,19 @@ public Int_t Int$choose(Int_t n, Int_t k)
return Int$from_mpz(ret);
}
-public Int_t Int$factorial(Int_t n)
-{
+public
+Int_t Int$factorial(Int_t n) {
mpz_t ret;
mpz_init(ret);
int64_t n_i64 = Int64$from_int(n, false);
- if unlikely (n_i64 < 0)
- fail("Factorials are not defined for negative numbers");
+ if unlikely (n_i64 < 0) fail("Factorials are not defined for negative numbers");
mpz_fac_ui(ret, (unsigned long)n_i64);
return Int$from_mpz(ret);
}
-static void Int$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *info)
-{
+static void Int$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *info) {
(void)info;
- Int_t i = *(Int_t*)obj;
+ Int_t i = *(Int_t *)obj;
if (likely(i.small & 1L)) {
fputc(0, out);
int64_t i64 = i.small >> 2L;
@@ -530,44 +511,45 @@ static void Int$serialize(const void *obj, FILE *out, Table_t *pointers, const T
} else {
fputc(1, out);
mpz_t n;
- mpz_init_set_int(n, *(Int_t*)obj);
+ mpz_init_set_int(n, *(Int_t *)obj);
mpz_out_raw(out, n);
}
}
-static void Int$deserialize(FILE *in, void *obj, List_t *pointers, const TypeInfo_t *info)
-{
+static void Int$deserialize(FILE *in, void *obj, List_t *pointers, const TypeInfo_t *info) {
(void)info;
if (fgetc(in) == 0) {
int64_t i = 0;
Int64$deserialize(in, &i, pointers, &Int64$info);
- *(Int_t*)obj = (Int_t){.small=(i<<2L) | 1L};
+ *(Int_t *)obj = (Int_t){.small = (i << 2L) | 1L};
} else {
mpz_t n;
mpz_init(n);
mpz_inp_raw(n, in);
- *(Int_t*)obj = Int$from_mpz(n);
+ *(Int_t *)obj = Int$from_mpz(n);
}
}
-public const TypeInfo_t Int$info = {
- .size=sizeof(Int_t),
- .align=__alignof__(Int_t),
- .metamethods={
- .compare=Int$compare,
- .equal=Int$equal,
- .hash=Int$hash,
- .as_text=Int$as_text,
- .is_none=Int$is_none,
- .serialize=Int$serialize,
- .deserialize=Int$deserialize,
- },
+public
+const TypeInfo_t Int$info = {
+ .size = sizeof(Int_t),
+ .align = __alignof__(Int_t),
+ .metamethods =
+ {
+ .compare = Int$compare,
+ .equal = Int$equal,
+ .hash = Int$hash,
+ .as_text = Int$as_text,
+ .is_none = Int$is_none,
+ .serialize = Int$serialize,
+ .deserialize = Int$deserialize,
+ },
};
-public void Int64$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *info)
-{
+public
+void Int64$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *info) {
(void)info, (void)pointers;
- int64_t i = *(int64_t*)obj;
+ int64_t i = *(int64_t *)obj;
uint64_t z = (uint64_t)((i << 1L) ^ (i >> 63L)); // Zigzag encode
while (z >= 0x80L) {
fputc((uint8_t)(z | 0x80L), out);
@@ -576,22 +558,22 @@ public void Int64$serialize(const void *obj, FILE *out, Table_t *pointers, const
fputc((uint8_t)z, out);
}
-public void Int64$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *info)
-{
+public
+void Int64$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *info) {
(void)info, (void)pointers;
uint64_t z = 0;
- for(size_t shift = 0; ; shift += 7) {
+ for (size_t shift = 0;; shift += 7) {
uint8_t byte = (uint8_t)fgetc(in);
z |= ((uint64_t)(byte & 0x7F)) << shift;
if ((byte & 0x80) == 0) break;
}
- *(int64_t*)outval = (int64_t)((z >> 1L) ^ -(z & 1L)); // Zigzag decode
+ *(int64_t *)outval = (int64_t)((z >> 1L) ^ -(z & 1L)); // Zigzag decode
}
-public void Int32$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *info)
-{
+public
+void Int32$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *info) {
(void)info, (void)pointers;
- int32_t i = *(int32_t*)obj;
+ int32_t i = *(int32_t *)obj;
uint32_t z = (uint32_t)((i << 1) ^ (i >> 31)); // Zigzag encode
while (z >= 0x80) {
fputc((uint8_t)(z | 0x80), out);
@@ -600,16 +582,16 @@ public void Int32$serialize(const void *obj, FILE *out, Table_t *pointers, const
fputc((uint8_t)z, out);
}
-public void Int32$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *info)
-{
+public
+void Int32$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *info) {
(void)info, (void)pointers;
uint32_t z = 0;
- for(size_t shift = 0; ; shift += 7) {
+ for (size_t shift = 0;; shift += 7) {
uint8_t byte = (uint8_t)fgetc(in);
z |= ((uint32_t)(byte & 0x7F)) << shift;
if ((byte & 0x80) == 0) break;
}
- *(int32_t*)outval = (int32_t)((z >> 1L) ^ -(z & 1L)); // Zigzag decode
+ *(int32_t *)outval = (int32_t)((z >> 1L) ^ -(z & 1L)); // Zigzag decode
}
// The space savings for smaller ints are not worth having:
@@ -619,122 +601,146 @@ public void Int32$deserialize(FILE *in, void *outval, List_t *pointers, const Ty
#define Int8$deserialize NULL
#ifdef __TINYC__
-#define __builtin_add_overflow(x, y, result) ({ *(result) = (x) + (y); false; })
+#define __builtin_add_overflow(x, y, result) \
+ ({ \
+ *(result) = (x) + (y); \
+ false; \
+ })
#endif
-#define DEFINE_INT_TYPE(c_type, KindOfInt, min_val, max_val, to_attr)\
- public Text_t KindOfInt ## $as_text(const void *i, bool colorize, const TypeInfo_t *info) { \
- (void)info; \
- if (!i) return Text(#KindOfInt); \
- Text_t text = _int64_to_text((int64_t)(*(c_type*)i)); \
- return colorize ? Texts(Text("\033[35m"), text, Text("\033[m")) : text; \
- } \
- public PUREFUNC int32_t KindOfInt ## $compare(const void *x, const void *y, const TypeInfo_t *info) { \
- (void)info; \
- return (*(c_type*)x > *(c_type*)y) - (*(c_type*)x < *(c_type*)y); \
- } \
- public PUREFUNC bool KindOfInt ## $equal(const void *x, const void *y, const TypeInfo_t *info) { \
- (void)info; \
- return *(c_type*)x == *(c_type*)y; \
- } \
- public CONSTFUNC bool KindOfInt ## $is_between(const c_type x, const c_type low, const c_type high) { \
- return low <= x && x <= high; \
- } \
- public CONSTFUNC c_type KindOfInt ## $clamped(c_type x, c_type min, c_type max) { \
- return x < min ? min : (x > max ? max : x); \
- } \
- public Text_t KindOfInt ## $hex(c_type i, Int_t digits_int, bool uppercase, bool prefix) { \
- Int_t as_int = Int$from_int64((int64_t)i); \
- return Int$hex(as_int, digits_int, uppercase, prefix); \
- } \
- public Text_t KindOfInt ## $octal(c_type i, Int_t digits_int, bool prefix) { \
- Int_t as_int = Int$from_int64((int64_t)i); \
- return Int$octal(as_int, digits_int, prefix); \
- } \
- public List_t KindOfInt ## $bits(c_type x) { \
- List_t bit_list = (List_t){.data=GC_MALLOC_ATOMIC(sizeof(bool[8*sizeof(c_type)])), .atomic=1, .stride=sizeof(bool), .length=8*sizeof(c_type)}; \
- bool *bits = bit_list.data + sizeof(c_type)*8; \
- for (size_t i = 0; i < 8*sizeof(c_type); i++) { \
- *(bits--) = x & 1; \
- x >>= 1; \
- } \
- return bit_list; \
- } \
- public bool KindOfInt ## $get_bit(c_type x, Int_t bit_index) { \
- if (Int$compare_value(bit_index, I(1)) < 0) \
- fail("Invalid bit index (expected 1 or higher): ", bit_index); \
- if (Int$compare_value(bit_index, Int$from_int64(sizeof(c_type)*8)) > 0) \
- fail("Bit index is too large! There are only ", (uint64_t)sizeof(c_type)*8, " bits, but index is: ", bit_index); \
- return ((x & (c_type)(1L << (Int64$from_int(bit_index, true)-1L))) != 0); \
- } \
- typedef struct { \
- Optional##KindOfInt##_t current, last; \
- KindOfInt##_t step; \
- } KindOfInt##Range_t; \
- static Optional##KindOfInt##_t _next_##KindOfInt(KindOfInt##Range_t *info) \
- { \
- Optional##KindOfInt##_t i = info->current; \
- if (!i.is_none) { \
- KindOfInt##_t next; bool overflow = __builtin_add_overflow(i.value, info->step, &next); \
- if (overflow || (!info->last.is_none && (info->step >= 0 ? next > info->last.value : next < info->last.value))) \
- info->current = (Optional##KindOfInt##_t){.is_none=true}; \
- else \
- info->current = (Optional##KindOfInt##_t){.value=next}; \
- } \
- return i; \
- } \
- public to_attr Closure_t KindOfInt ## $to(c_type first, c_type last, Optional ## KindOfInt ## _t step) { \
- KindOfInt##Range_t *range = GC_MALLOC(sizeof(KindOfInt##Range_t)); \
- range->current = (Optional##KindOfInt##_t){.value=first}; \
- range->last = (Optional##KindOfInt##_t){.value=last}; \
- range->step = step.is_none ? (last >= first ? 1 : -1) : step.value; \
- return (Closure_t){.fn=_next_##KindOfInt, .userdata=range}; \
- } \
- public to_attr Closure_t KindOfInt ## $onward(c_type first, c_type step) { \
- KindOfInt##Range_t *range = GC_MALLOC(sizeof(KindOfInt##Range_t)); \
- range->current = (Optional##KindOfInt##_t){.value=first}; \
- range->last = (Optional##KindOfInt##_t){.is_none=true}; \
- range->step = step; \
- return (Closure_t){.fn=_next_##KindOfInt, .userdata=range}; \
- } \
- public PUREFUNC Optional ## KindOfInt ## _t KindOfInt ## $parse(Text_t text, Text_t *remainder) { \
- OptionalInt_t full_int = Int$parse(text, remainder); \
- if (full_int.small == 0L) return (Optional ## KindOfInt ## _t){.is_none=true}; \
- if (Int$compare_value(full_int, I(min_val)) < 0) { \
- return (Optional ## KindOfInt ## _t){.is_none=true}; \
- } \
- if (Int$compare_value(full_int, I(max_val)) > 0) { \
- return (Optional ## KindOfInt ## _t){.is_none=true}; \
- } \
- return (Optional ## KindOfInt ## _t){.value=KindOfInt##$from_int(full_int, true)}; \
- } \
- public CONSTFUNC c_type KindOfInt ## $gcd(c_type x, c_type y) { \
- if (x == 0 || y == 0) return 0; \
- x = KindOfInt##$abs(x); \
- y = KindOfInt##$abs(y); \
- while (x != y) { \
- if (x > y) x -= y; \
- else y -= x; \
- } \
- return x; \
- } \
- public const c_type KindOfInt##$min = min_val; \
- public const c_type KindOfInt##$max = max_val; \
- public const TypeInfo_t KindOfInt##$info = { \
- .size=sizeof(c_type), \
- .align=__alignof__(c_type), \
- .metamethods={ \
- .compare=KindOfInt##$compare, \
- .as_text=KindOfInt##$as_text, \
- .serialize=KindOfInt##$serialize, \
- .deserialize=KindOfInt##$deserialize, \
- }, \
+#define DEFINE_INT_TYPE(c_type, KindOfInt, min_val, max_val, to_attr) \
+ public \
+ Text_t KindOfInt##$as_text(const void *i, bool colorize, const TypeInfo_t *info) { \
+ (void)info; \
+ if (!i) return Text(#KindOfInt); \
+ Text_t text = _int64_to_text((int64_t)(*(c_type *)i)); \
+ return colorize ? Texts(Text("\033[35m"), text, Text("\033[m")) : text; \
+ } \
+ public \
+ PUREFUNC int32_t KindOfInt##$compare(const void *x, const void *y, const TypeInfo_t *info) { \
+ (void)info; \
+ return (*(c_type *)x > *(c_type *)y) - (*(c_type *)x < *(c_type *)y); \
+ } \
+ public \
+ PUREFUNC bool KindOfInt##$equal(const void *x, const void *y, const TypeInfo_t *info) { \
+ (void)info; \
+ return *(c_type *)x == *(c_type *)y; \
+ } \
+ public \
+ CONSTFUNC bool KindOfInt##$is_between(const c_type x, const c_type low, const c_type high) { \
+ return low <= x && x <= high; \
+ } \
+ public \
+ CONSTFUNC c_type KindOfInt##$clamped(c_type x, c_type min, c_type max) { \
+ return x < min ? min : (x > max ? max : x); \
+ } \
+ public \
+ Text_t KindOfInt##$hex(c_type i, Int_t digits_int, bool uppercase, bool prefix) { \
+ Int_t as_int = Int$from_int64((int64_t)i); \
+ return Int$hex(as_int, digits_int, uppercase, prefix); \
+ } \
+ public \
+ Text_t KindOfInt##$octal(c_type i, Int_t digits_int, bool prefix) { \
+ Int_t as_int = Int$from_int64((int64_t)i); \
+ return Int$octal(as_int, digits_int, prefix); \
+ } \
+ public \
+ List_t KindOfInt##$bits(c_type x) { \
+ List_t bit_list = (List_t){.data = GC_MALLOC_ATOMIC(sizeof(bool[8 * sizeof(c_type)])), \
+ .atomic = 1, \
+ .stride = sizeof(bool), \
+ .length = 8 * sizeof(c_type)}; \
+ bool *bits = bit_list.data + sizeof(c_type) * 8; \
+ for (size_t i = 0; i < 8 * sizeof(c_type); i++) { \
+ *(bits--) = x & 1; \
+ x >>= 1; \
+ } \
+ return bit_list; \
+ } \
+ public \
+ bool KindOfInt##$get_bit(c_type x, Int_t bit_index) { \
+ if (Int$compare_value(bit_index, I(1)) < 0) fail("Invalid bit index (expected 1 or higher): ", bit_index); \
+ if (Int$compare_value(bit_index, Int$from_int64(sizeof(c_type) * 8)) > 0) \
+ fail("Bit index is too large! There are only ", (uint64_t)sizeof(c_type) * 8, \
+ " bits, but index is: ", bit_index); \
+ return ((x & (c_type)(1L << (Int64$from_int(bit_index, true) - 1L))) != 0); \
+ } \
+ typedef struct { \
+ Optional##KindOfInt##_t current, last; \
+ KindOfInt##_t step; \
+ } KindOfInt##Range_t; \
+ static Optional##KindOfInt##_t _next_##KindOfInt(KindOfInt##Range_t *info) { \
+ Optional##KindOfInt##_t i = info->current; \
+ if (!i.is_none) { \
+ KindOfInt##_t next; \
+ bool overflow = __builtin_add_overflow(i.value, info->step, &next); \
+ if (overflow \
+ || (!info->last.is_none && (info->step >= 0 ? next > info->last.value : next < info->last.value))) \
+ info->current = (Optional##KindOfInt##_t){.is_none = true}; \
+ else info->current = (Optional##KindOfInt##_t){.value = next}; \
+ } \
+ return i; \
+ } \
+ public \
+ to_attr Closure_t KindOfInt##$to(c_type first, c_type last, Optional##KindOfInt##_t step) { \
+ KindOfInt##Range_t *range = GC_MALLOC(sizeof(KindOfInt##Range_t)); \
+ range->current = (Optional##KindOfInt##_t){.value = first}; \
+ range->last = (Optional##KindOfInt##_t){.value = last}; \
+ range->step = step.is_none ? (last >= first ? 1 : -1) : step.value; \
+ return (Closure_t){.fn = _next_##KindOfInt, .userdata = range}; \
+ } \
+ public \
+ to_attr Closure_t KindOfInt##$onward(c_type first, c_type step) { \
+ KindOfInt##Range_t *range = GC_MALLOC(sizeof(KindOfInt##Range_t)); \
+ range->current = (Optional##KindOfInt##_t){.value = first}; \
+ range->last = (Optional##KindOfInt##_t){.is_none = true}; \
+ range->step = step; \
+ return (Closure_t){.fn = _next_##KindOfInt, .userdata = range}; \
+ } \
+ public \
+ PUREFUNC Optional##KindOfInt##_t KindOfInt##$parse(Text_t text, Text_t *remainder) { \
+ OptionalInt_t full_int = Int$parse(text, remainder); \
+ if (full_int.small == 0L) return (Optional##KindOfInt##_t){.is_none = true}; \
+ if (Int$compare_value(full_int, I(min_val)) < 0) { \
+ return (Optional##KindOfInt##_t){.is_none = true}; \
+ } \
+ if (Int$compare_value(full_int, I(max_val)) > 0) { \
+ return (Optional##KindOfInt##_t){.is_none = true}; \
+ } \
+ return (Optional##KindOfInt##_t){.value = KindOfInt##$from_int(full_int, true)}; \
+ } \
+ public \
+ CONSTFUNC c_type KindOfInt##$gcd(c_type x, c_type y) { \
+ if (x == 0 || y == 0) return 0; \
+ x = KindOfInt##$abs(x); \
+ y = KindOfInt##$abs(y); \
+ while (x != y) { \
+ if (x > y) x -= y; \
+ else y -= x; \
+ } \
+ return x; \
+ } \
+ public \
+ const c_type KindOfInt##$min = min_val; \
+ public \
+ const c_type KindOfInt##$max = max_val; \
+ public \
+ const TypeInfo_t KindOfInt##$info = { \
+ .size = sizeof(c_type), \
+ .align = __alignof__(c_type), \
+ .metamethods = \
+ { \
+ .compare = KindOfInt##$compare, \
+ .as_text = KindOfInt##$as_text, \
+ .serialize = KindOfInt##$serialize, \
+ .deserialize = KindOfInt##$deserialize, \
+ }, \
};
-DEFINE_INT_TYPE(int64_t, Int64, INT64_MIN, INT64_MAX, __attribute__(()))
-DEFINE_INT_TYPE(int32_t, Int32, INT32_MIN, INT32_MAX, CONSTFUNC)
-DEFINE_INT_TYPE(int16_t, Int16, INT16_MIN, INT16_MAX, CONSTFUNC)
-DEFINE_INT_TYPE(int8_t, Int8, INT8_MIN, INT8_MAX, CONSTFUNC)
+DEFINE_INT_TYPE(int64_t, Int64, INT64_MIN, INT64_MAX, __attribute__(()))
+DEFINE_INT_TYPE(int32_t, Int32, INT32_MIN, INT32_MAX, CONSTFUNC)
+DEFINE_INT_TYPE(int16_t, Int16, INT16_MIN, INT16_MAX, CONSTFUNC)
+DEFINE_INT_TYPE(int8_t, Int8, INT8_MIN, INT8_MAX, CONSTFUNC)
#undef DEFINE_INT_TYPE
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/stdlib/integers.h b/src/stdlib/integers.h
index 744992dd..a7249495 100644
--- a/src/stdlib/integers.h
+++ b/src/stdlib/integers.h
@@ -2,9 +2,9 @@
// Integer type infos and methods
+#include <gmp.h>
#include <stdbool.h>
#include <stdint.h>
-#include <gmp.h>
#include "datatypes.h"
#include "stdlib.h"
@@ -16,74 +16,72 @@
#define I16(x) ((int16_t)x)
#define I8(x) ((int8_t)x)
-#define DEFINE_INT_TYPE(c_type, type_name) \
- typedef struct { \
- c_type value; \
- bool is_none:1; \
- } Optional ## type_name ## _t; \
- Text_t type_name ## $as_text(const void *i, bool colorize, const TypeInfo_t *type); \
- PUREFUNC int32_t type_name ## $compare(const void *x, const void *y, const TypeInfo_t *type); \
- PUREFUNC bool type_name ## $equal(const void *x, const void *y, const TypeInfo_t *type); \
- Text_t type_name ## $hex(c_type i, Int_t digits, bool uppercase, bool prefix); \
- Text_t type_name ## $octal(c_type i, Int_t digits, bool prefix); \
- List_t type_name ## $bits(c_type x); \
- bool type_name ## $get_bit(c_type x, Int_t bit_index); \
- Closure_t type_name ## $to(c_type first, c_type last, Optional ## type_name ## _t step); \
- Closure_t type_name ## $onward(c_type first, c_type step); \
- PUREFUNC Optional ## type_name ## _t type_name ## $parse(Text_t text, Text_t *remainder); \
- CONSTFUNC bool type_name ## $is_between(const c_type x, const c_type low, const c_type high); \
- CONSTFUNC c_type type_name ## $clamped(c_type x, c_type min, c_type max); \
- MACROLIKE CONSTFUNC c_type type_name ## $from_byte(Byte_t b) { return (c_type)b; } \
- MACROLIKE CONSTFUNC c_type type_name ## $from_bool(Bool_t b) { return (c_type)b; } \
- CONSTFUNC c_type type_name ## $gcd(c_type x, c_type y); \
- extern const c_type type_name ## $min, type_name##$max; \
- extern const TypeInfo_t type_name ## $info; \
- MACROLIKE c_type type_name ## $divided_by(c_type D, c_type d) { \
- c_type q = D/d, r = D%d; \
- q -= (r < 0) * (2*(d > 0) - 1); \
- return q; \
- } \
- MACROLIKE c_type type_name ## $modulo(c_type D, c_type d) { \
- c_type r = D%d; \
- r -= (r < 0) * (2*(d < 0) - 1) * d; \
- return r; \
- } \
- MACROLIKE c_type type_name ## $modulo1(c_type D, c_type d) { \
- return type_name ## $modulo(D-1, d) + 1; \
- } \
- MACROLIKE PUREFUNC c_type type_name ## $wrapping_plus(c_type x, c_type y) { \
- return (c_type)((u##c_type)x + (u##c_type)y); \
- } \
- MACROLIKE PUREFUNC c_type type_name ## $wrapping_minus(c_type x, c_type y) { \
- return (c_type)((u##c_type)x + (u##c_type)y); \
- } \
- MACROLIKE PUREFUNC c_type type_name ## $unsigned_left_shifted(c_type x, c_type y) { \
- return (c_type)((u##c_type)x << y); \
- } \
- MACROLIKE PUREFUNC c_type type_name ## $unsigned_right_shifted(c_type x, c_type y) { \
- return (c_type)((u##c_type)x >> y); \
+#define DEFINE_INT_TYPE(c_type, type_name) \
+ typedef struct { \
+ c_type value; \
+ bool is_none : 1; \
+ } Optional##type_name##_t; \
+ Text_t type_name##$as_text(const void *i, bool colorize, const TypeInfo_t *type); \
+ PUREFUNC int32_t type_name##$compare(const void *x, const void *y, const TypeInfo_t *type); \
+ PUREFUNC bool type_name##$equal(const void *x, const void *y, const TypeInfo_t *type); \
+ Text_t type_name##$hex(c_type i, Int_t digits, bool uppercase, bool prefix); \
+ Text_t type_name##$octal(c_type i, Int_t digits, bool prefix); \
+ List_t type_name##$bits(c_type x); \
+ bool type_name##$get_bit(c_type x, Int_t bit_index); \
+ Closure_t type_name##$to(c_type first, c_type last, Optional##type_name##_t step); \
+ Closure_t type_name##$onward(c_type first, c_type step); \
+ PUREFUNC Optional##type_name##_t type_name##$parse(Text_t text, Text_t *remainder); \
+ CONSTFUNC bool type_name##$is_between(const c_type x, const c_type low, const c_type high); \
+ CONSTFUNC c_type type_name##$clamped(c_type x, c_type min, c_type max); \
+ MACROLIKE CONSTFUNC c_type type_name##$from_byte(Byte_t b) { return (c_type)b; } \
+ MACROLIKE CONSTFUNC c_type type_name##$from_bool(Bool_t b) { return (c_type)b; } \
+ CONSTFUNC c_type type_name##$gcd(c_type x, c_type y); \
+ extern const c_type type_name##$min, type_name##$max; \
+ extern const TypeInfo_t type_name##$info; \
+ MACROLIKE c_type type_name##$divided_by(c_type D, c_type d) { \
+ c_type q = D / d, r = D % d; \
+ q -= (r < 0) * (2 * (d > 0) - 1); \
+ return q; \
+ } \
+ MACROLIKE c_type type_name##$modulo(c_type D, c_type d) { \
+ c_type r = D % d; \
+ r -= (r < 0) * (2 * (d < 0) - 1) * d; \
+ return r; \
+ } \
+ MACROLIKE c_type type_name##$modulo1(c_type D, c_type d) { return type_name##$modulo(D - 1, d) + 1; } \
+ MACROLIKE PUREFUNC c_type type_name##$wrapping_plus(c_type x, c_type y) { \
+ return (c_type)((u##c_type)x + (u##c_type)y); \
+ } \
+ MACROLIKE PUREFUNC c_type type_name##$wrapping_minus(c_type x, c_type y) { \
+ return (c_type)((u##c_type)x + (u##c_type)y); \
+ } \
+ MACROLIKE PUREFUNC c_type type_name##$unsigned_left_shifted(c_type x, c_type y) { \
+ return (c_type)((u##c_type)x << y); \
+ } \
+ MACROLIKE PUREFUNC c_type type_name##$unsigned_right_shifted(c_type x, c_type y) { \
+ return (c_type)((u##c_type)x >> y); \
}
DEFINE_INT_TYPE(int64_t, Int64)
DEFINE_INT_TYPE(int32_t, Int32)
DEFINE_INT_TYPE(int16_t, Int16)
-DEFINE_INT_TYPE(int8_t, Int8)
+DEFINE_INT_TYPE(int8_t, Int8)
#undef DEFINE_INT_TYPE
-#define NONE_INT64 ((OptionalInt64_t){.is_none=true})
-#define NONE_INT32 ((OptionalInt32_t){.is_none=true})
-#define NONE_INT16 ((OptionalInt16_t){.is_none=true})
-#define NONE_INT8 ((OptionalInt8_t){.is_none=true})
+#define NONE_INT64 ((OptionalInt64_t){.is_none = true})
+#define NONE_INT32 ((OptionalInt32_t){.is_none = true})
+#define NONE_INT16 ((OptionalInt16_t){.is_none = true})
+#define NONE_INT8 ((OptionalInt8_t){.is_none = true})
#define Int64$abs(...) I64(labs(__VA_ARGS__))
#define Int32$abs(...) I32(abs(__VA_ARGS__))
#define Int16$abs(...) I16(abs(__VA_ARGS__))
#define Int8$abs(...) I8(abs(__VA_ARGS__))
-void Int64$serialize(const void *obj, FILE *out, Table_t*, const TypeInfo_t*);
-void Int64$deserialize(FILE *in, void *outval, List_t*, const TypeInfo_t*);
-void Int32$serialize(const void *obj, FILE *out, Table_t*, const TypeInfo_t*);
-void Int32$deserialize(FILE *in, void *outval, List_t*, const TypeInfo_t*);
+void Int64$serialize(const void *obj, FILE *out, Table_t *, const TypeInfo_t *);
+void Int64$deserialize(FILE *in, void *outval, List_t *, const TypeInfo_t *);
+void Int32$serialize(const void *obj, FILE *out, Table_t *, const TypeInfo_t *);
+void Int32$deserialize(FILE *in, void *outval, List_t *, const TypeInfo_t *);
Text_t Int$as_text(const void *i, bool colorize, const TypeInfo_t *type);
Text_t Int$value_as_text(Int_t i);
@@ -109,19 +107,17 @@ bool Int$get_bit(Int_t x, Int_t bit_index);
#define BIGGEST_SMALL_INT 0x3fffffff
#define SMALLEST_SMALL_INT -0x40000000
-#define Int$from_mpz(mpz) (\
- mpz_cmpabs_ui(mpz, BIGGEST_SMALL_INT) <= 0 ? ( \
- (Int_t){.small=(mpz_get_si(mpz)<<2L)|1L} \
- ) : ( \
- (Int_t){.big=memcpy(new(mpz_t), &mpz, sizeof(mpz_t))} \
- ))
+#define Int$from_mpz(mpz) \
+ (mpz_cmpabs_ui(mpz, BIGGEST_SMALL_INT) <= 0 ? ((Int_t){.small = (mpz_get_si(mpz) << 2L) | 1L}) \
+ : ((Int_t){.big = memcpy(new (mpz_t), &mpz, sizeof(mpz_t))}))
-#define mpz_init_set_int(mpz, i) do { \
- if likely ((i).small & 1L) mpz_init_set_si(mpz, (i).small >> 2L); \
- else mpz_init_set(mpz, *(i).big); \
-} while (0)
+#define mpz_init_set_int(mpz, i) \
+ do { \
+ if likely ((i).small & 1L) mpz_init_set_si(mpz, (i).small >> 2L); \
+ else mpz_init_set(mpz, *(i).big); \
+ } while (0)
-#define I_small(i) ((Int_t){.small=(int64_t)((uint64_t)(i)<<2L)|1L})
+#define I_small(i) ((Int_t){.small = (int64_t)((uint64_t)(i) << 2L) | 1L})
#define I(i) _Generic(i, int8_t: I_small(i), int16_t: I_small(i), default: Int$from_int64(i))
#define I_is_zero(i) ((i).small == 1L)
@@ -155,116 +151,107 @@ extern const TypeInfo_t Int$info;
MACROLIKE Int_t Int$plus(Int_t x, Int_t y) {
const int64_t z = (int64_t)((uint64_t)x.small + (uint64_t)y.small);
- if likely ((z|2L) == (int32_t)z)
- return (Int_t){.small=(z-1L)};
+ if likely ((z | 2L) == (int32_t)z) return (Int_t){.small = (z - 1L)};
return Int$slow_plus(x, y);
}
MACROLIKE Int_t Int$minus(Int_t x, Int_t y) {
const int64_t z = (int64_t)(((uint64_t)x.small ^ 3L) - (uint64_t)y.small);
- if likely ((z & ~2L) == (int32_t)z)
- return (Int_t){.small=z};
+ if likely ((z & ~2L) == (int32_t)z) return (Int_t){.small = z};
return Int$slow_minus(x, y);
}
MACROLIKE Int_t Int$times(Int_t x, Int_t y) {
if likely ((x.small & y.small) & 1L) {
- const int64_t z = (x.small>>1L) * (y.small>>1L);
- if likely (z == (int32_t)z)
- return (Int_t){.small=z+1L};
+ const int64_t z = (x.small >> 1L) * (y.small >> 1L);
+ if likely (z == (int32_t)z) return (Int_t){.small = z + 1L};
}
return Int$slow_times(x, y);
}
MACROLIKE Int_t Int$divided_by(Int_t x, Int_t y) {
if likely (x.small & y.small & 1L) {
- // Euclidean division, see: https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf
- const int64_t D = (x.small>>2L);
- const int64_t d = (y.small>>2L);
- int64_t q = D/d, r = D%d;
- q -= (r < 0L) * (2L*(d > 0L) - 1L);
- if likely (q == (int32_t)q)
- return (Int_t){.small=(q<<2L)|1L};
+ // Euclidean division, see:
+ // https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf
+ const int64_t D = (x.small >> 2L);
+ const int64_t d = (y.small >> 2L);
+ int64_t q = D / d, r = D % d;
+ q -= (r < 0L) * (2L * (d > 0L) - 1L);
+ if likely (q == (int32_t)q) return (Int_t){.small = (q << 2L) | 1L};
}
return Int$slow_divided_by(x, y);
}
MACROLIKE Int_t Int$modulo(Int_t x, Int_t y) {
if likely (x.small & y.small & 1L) {
- // Euclidean modulus, see: https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf
- const int64_t D = (x.small>>2L);
- const int64_t d = (y.small>>2L);
- int64_t r = D%d;
- r -= (r < 0L) * (2L*(d < 0L) - 1L) * d;
- return (Int_t){.small=(r<<2L)|1L};
+ // Euclidean modulus, see:
+ // https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf
+ const int64_t D = (x.small >> 2L);
+ const int64_t d = (y.small >> 2L);
+ int64_t r = D % d;
+ r -= (r < 0L) * (2L * (d < 0L) - 1L) * d;
+ return (Int_t){.small = (r << 2L) | 1L};
}
return Int$slow_modulo(x, y);
}
MACROLIKE Int_t Int$modulo1(Int_t x, Int_t y) {
if likely (x.small & y.small & 1L) {
- // Euclidean modulus, see: https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf
- const int64_t D = (x.small>>2L)-1L;
- const int64_t d = (y.small>>2L);
- int64_t r = D%d;
- r -= (r < 0L) * (2L*(d < 0L) - 1L) * d;
- return (Int_t){.small=((r+1L)<<2L)|1L};
+ // Euclidean modulus, see:
+ // https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf
+ const int64_t D = (x.small >> 2L) - 1L;
+ const int64_t d = (y.small >> 2L);
+ int64_t r = D % d;
+ r -= (r < 0L) * (2L * (d < 0L) - 1L) * d;
+ return (Int_t){.small = ((r + 1L) << 2L) | 1L};
}
return Int$slow_modulo1(x, y);
}
MACROLIKE Int_t Int$left_shifted(Int_t x, Int_t y) {
if likely (x.small & y.small & 1L) {
- const int64_t z = ((x.small>>2L) << (y.small>>2L))<<2L;
- if likely (z == (int32_t)z)
- return (Int_t){.small=z+1L};
+ const int64_t z = ((x.small >> 2L) << (y.small >> 2L)) << 2L;
+ if likely (z == (int32_t)z) return (Int_t){.small = z + 1L};
}
return Int$slow_left_shifted(x, y);
}
MACROLIKE Int_t Int$right_shifted(Int_t x, Int_t y) {
if likely (x.small & y.small & 1L) {
- const int64_t z = ((x.small>>2L) >> (y.small>>2L))<<2L;
- if likely (z == (int32_t)z)
- return (Int_t){.small=z+1L};
+ const int64_t z = ((x.small >> 2L) >> (y.small >> 2L)) << 2L;
+ if likely (z == (int32_t)z) return (Int_t){.small = z + 1L};
}
return Int$slow_right_shifted(x, y);
}
MACROLIKE Int_t Int$bit_and(Int_t x, Int_t y) {
const int64_t z = x.small & y.small;
- if likely (z & 1L)
- return (Int_t){.small=z};
+ if likely (z & 1L) return (Int_t){.small = z};
return Int$slow_bit_and(x, y);
}
MACROLIKE Int_t Int$bit_or(Int_t x, Int_t y) {
- if likely (x.small & y.small & 1L)
- return (Int_t){.small=(x.small | y.small)};
+ if likely (x.small & y.small & 1L) return (Int_t){.small = (x.small | y.small)};
return Int$slow_bit_or(x, y);
}
MACROLIKE Int_t Int$bit_xor(Int_t x, Int_t y) {
- if likely (x.small & y.small & 1L)
- return (Int_t){.small=(x.small ^ y.small) | 1L};
+ if likely (x.small & y.small & 1L) return (Int_t){.small = (x.small ^ y.small) | 1L};
return Int$slow_bit_xor(x, y);
}
MACROLIKE Int_t Int$negated(Int_t x) {
- if likely (x.small & 1L)
- return (Int_t){.small=(~x.small) ^ 3L};
+ if likely (x.small & 1L) return (Int_t){.small = (~x.small) ^ 3L};
return Int$slow_negated(x);
}
MACROLIKE Int_t Int$negative(Int_t x) {
- if likely (x.small & 1L)
- return (Int_t){.small=((-((x.small)>>2L))<<2L) | 1L};
+ if likely (x.small & 1L) return (Int_t){.small = ((-((x.small) >> 2L)) << 2L) | 1L};
return Int$slow_negative(x);
}
MACROLIKE PUREFUNC bool Int$is_negative(Int_t x) {
- if likely (x.small & 1L)
- return x.small < 0L;
+ if likely (x.small & 1L) return x.small < 0L;
return Int$compare_value(x, I_small(0)) < 0L;
}
@@ -278,42 +265,36 @@ MACROLIKE PUREFUNC bool Int$is_negative(Int_t x) {
MACROLIKE PUREFUNC Int_t Int$from_num(double n, bool truncate) {
mpz_t result;
mpz_init_set_d(result, n);
- if (!truncate && unlikely(mpz_get_d(result) != n))
- fail("Could not convert to an integer without truncation: ", n);
+ if (!truncate && unlikely(mpz_get_d(result) != n)) fail("Could not convert to an integer without truncation: ", n);
return Int$from_mpz(result);
}
MACROLIKE PUREFUNC Int_t Int$from_num32(float n, bool truncate) { return Int$from_num((double)n, truncate); }
MACROLIKE Int_t Int$from_int64(int64_t i) {
- if likely (i >= SMALLEST_SMALL_INT && i <= BIGGEST_SMALL_INT)
- return (Int_t){.small=(i<<2L)|1L};
+ if likely (i >= SMALLEST_SMALL_INT && i <= BIGGEST_SMALL_INT) return (Int_t){.small = (i << 2L) | 1L};
mpz_t result;
mpz_init_set_si(result, i);
return Int$from_mpz(result);
}
MACROLIKE CONSTFUNC Int_t Int$from_int32(Int32_t i) { return Int$from_int64((Int32_t)i); }
MACROLIKE CONSTFUNC Int_t Int$from_int16(Int16_t i) { return I_small(i); }
-MACROLIKE CONSTFUNC Int_t Int$from_int8(Int8_t i) { return I_small(i); }
+MACROLIKE CONSTFUNC Int_t Int$from_int8(Int8_t i) { return I_small(i); }
MACROLIKE CONSTFUNC Int_t Int$from_byte(Byte_t b) { return I_small(b); }
MACROLIKE CONSTFUNC Int_t Int$from_bool(Bool_t b) { return I_small(b); }
// Int64 constructors
MACROLIKE PUREFUNC Int64_t Int64$from_num(Num_t n, bool truncate) {
int64_t i64 = (int64_t)n;
- if (!truncate && unlikely((Num_t)i64 != n))
- fail("Could not convert Num to Int64 without truncation: ", n);
+ if (!truncate && unlikely((Num_t)i64 != n)) fail("Could not convert Num to Int64 without truncation: ", n);
return i64;
}
MACROLIKE PUREFUNC Int64_t Int64$from_num32(Num32_t n, bool truncate) {
int64_t i64 = (int64_t)n;
- if (!truncate && unlikely((Num32_t)i64 != n))
- fail("Could not convert Num32 to Int64 without truncation: ", n);
+ if (!truncate && unlikely((Num32_t)i64 != n)) fail("Could not convert Num32 to Int64 without truncation: ", n);
return i64;
}
MACROLIKE PUREFUNC Int64_t Int64$from_int(Int_t i, bool truncate) {
- if likely (i.small & 1L)
- return (int64_t)(i.small >> 2L);
- if (!truncate && unlikely(!mpz_fits_slong_p(*i.big)))
- fail("Integer is too big to fit in a 64-bit integer: ", i);
+ if likely (i.small & 1L) return (int64_t)(i.small >> 2L);
+ if (!truncate && unlikely(!mpz_fits_slong_p(*i.big))) fail("Integer is too big to fit in a 64-bit integer: ", i);
return mpz_get_si(*i.big);
}
MACROLIKE CONSTFUNC Int64_t Int64$from_int32(Int32_t i) { return (Int64_t)i; }
@@ -323,27 +304,23 @@ MACROLIKE CONSTFUNC Int64_t Int64$from_int8(Int8_t i) { return (Int64_t)i; }
// Int32 constructors
MACROLIKE PUREFUNC Int32_t Int32$from_num(Num_t n, bool truncate) {
int32_t i32 = (int32_t)n;
- if (!truncate && unlikely((Num_t)i32 != n))
- fail("Could not convert Num to Int32 without truncation: ", n);
+ if (!truncate && unlikely((Num_t)i32 != n)) fail("Could not convert Num to Int32 without truncation: ", n);
return i32;
}
MACROLIKE PUREFUNC Int32_t Int32$from_num32(Num32_t n, bool truncate) {
int32_t i32 = (int32_t)n;
- if (!truncate && unlikely((Num32_t)i32 != n))
- fail("Could not convert Num32 to Int32 without truncation: ", n);
+ if (!truncate && unlikely((Num32_t)i32 != n)) fail("Could not convert Num32 to Int32 without truncation: ", n);
return i32;
}
MACROLIKE PUREFUNC Int32_t Int32$from_int(Int_t i, bool truncate) {
int64_t i64 = Int64$from_int(i, truncate);
int32_t i32 = (int32_t)i64;
- if (!truncate && unlikely((int64_t)i32 != i64))
- fail("Integer is too big to fit in a 32-bit integer: ", i);
+ if (!truncate && unlikely((int64_t)i32 != i64)) fail("Integer is too big to fit in a 32-bit integer: ", i);
return i32;
}
MACROLIKE PUREFUNC Int32_t Int32$from_int64(Int64_t i64, bool truncate) {
int32_t i32 = (int32_t)i64;
- if (!truncate && unlikely((int64_t)i32 != i64))
- fail("Integer is too big to fit in a 32-bit integer: ", i64);
+ if (!truncate && unlikely((int64_t)i32 != i64)) fail("Integer is too big to fit in a 32-bit integer: ", i64);
return i32;
}
MACROLIKE CONSTFUNC Int32_t Int32$from_int16(Int16_t i) { return (Int32_t)i; }
@@ -352,8 +329,7 @@ MACROLIKE CONSTFUNC Int32_t Int32$from_int8(Int8_t i) { return (Int32_t)i; }
// Int16 constructors
MACROLIKE PUREFUNC Int16_t Int16$from_num(Num_t n, bool truncate) {
int16_t i16 = (int16_t)n;
- if (!truncate && unlikely((Num_t)i16 != n))
- fail("Could not convert Num to Int16 without truncation: ", n);
+ if (!truncate && unlikely((Num_t)i16 != n)) fail("Could not convert Num to Int16 without truncation: ", n);
return i16;
}
MACROLIKE PUREFUNC Int16_t Int16$from_num32(Num32_t n, bool truncate) {
@@ -365,20 +341,17 @@ MACROLIKE PUREFUNC Int16_t Int16$from_num32(Num32_t n, bool truncate) {
MACROLIKE PUREFUNC Int16_t Int16$from_int(Int_t i, bool truncate) {
int64_t i64 = Int64$from_int(i, truncate);
int16_t i16 = (int16_t)i64;
- if (!truncate && unlikely((int64_t)i16 != i64))
- fail("Integer is too big to fit in a 16-bit integer!");
+ if (!truncate && unlikely((int64_t)i16 != i64)) fail("Integer is too big to fit in a 16-bit integer!");
return i16;
}
MACROLIKE PUREFUNC Int16_t Int16$from_int64(Int64_t i64, bool truncate) {
int16_t i16 = (int16_t)i64;
- if (!truncate && unlikely((int64_t)i16 != i64))
- fail("Integer is too big to fit in a 16-bit integer: ", i64);
+ if (!truncate && unlikely((int64_t)i16 != i64)) fail("Integer is too big to fit in a 16-bit integer: ", i64);
return i16;
}
MACROLIKE PUREFUNC Int16_t Int16$from_int32(Int32_t i32, bool truncate) {
int16_t i16 = (int16_t)i32;
- if (!truncate && unlikely((int32_t)i16 != i32))
- fail("Integer is too big to fit in a 16-bit integer: ", i32);
+ if (!truncate && unlikely((int32_t)i16 != i32)) fail("Integer is too big to fit in a 16-bit integer: ", i32);
return i16;
}
MACROLIKE CONSTFUNC Int16_t Int16$from_int8(Int8_t i) { return (Int16_t)i; }
@@ -386,39 +359,33 @@ MACROLIKE CONSTFUNC Int16_t Int16$from_int8(Int8_t i) { return (Int16_t)i; }
// Int8 constructors
MACROLIKE PUREFUNC Int8_t Int8$from_num(Num_t n, bool truncate) {
int8_t i8 = (int8_t)n;
- if (!truncate && unlikely((Num_t)i8 != n))
- fail("Could not convert Num to Int8 without truncation: ", n);
+ if (!truncate && unlikely((Num_t)i8 != n)) fail("Could not convert Num to Int8 without truncation: ", n);
return i8;
}
MACROLIKE PUREFUNC Int8_t Int8$from_num32(Num32_t n, bool truncate) {
int8_t i8 = (int8_t)n;
- if (!truncate && unlikely((Num32_t)i8 != n))
- fail("Could not convert Num32 to Int8 without truncation: ", n);
+ if (!truncate && unlikely((Num32_t)i8 != n)) fail("Could not convert Num32 to Int8 without truncation: ", n);
return i8;
}
MACROLIKE PUREFUNC Int8_t Int8$from_int(Int_t i, bool truncate) {
int64_t i64 = Int64$from_int(i, truncate);
int8_t i8 = (int8_t)i64;
- if (!truncate && unlikely((int64_t)i8 != i64))
- fail("Integer is too big to fit in an 8-bit integer!");
+ if (!truncate && unlikely((int64_t)i8 != i64)) fail("Integer is too big to fit in an 8-bit integer!");
return i8;
}
MACROLIKE PUREFUNC Int8_t Int8$from_int64(Int64_t i64, bool truncate) {
int8_t i8 = (int8_t)i64;
- if (!truncate && unlikely((int64_t)i8 != i64))
- fail("Integer is too big to fit in a 8-bit integer: ", i64);
+ if (!truncate && unlikely((int64_t)i8 != i64)) fail("Integer is too big to fit in a 8-bit integer: ", i64);
return i8;
}
MACROLIKE PUREFUNC Int8_t Int8$from_int32(Int32_t i32, bool truncate) {
int8_t i8 = (int8_t)i32;
- if (!truncate && unlikely((int32_t)i8 != i32))
- fail("Integer is too big to fit in a 8-bit integer: ", i32);
+ if (!truncate && unlikely((int32_t)i8 != i32)) fail("Integer is too big to fit in a 8-bit integer: ", i32);
return i8;
}
MACROLIKE PUREFUNC Int8_t Int8$from_int16(Int16_t i16, bool truncate) {
int8_t i8 = (int8_t)i16;
- if (!truncate && unlikely((int16_t)i8 != i16))
- fail("Integer is too big to fit in a 8-bit integer: ", i16);
+ if (!truncate && unlikely((int16_t)i8 != i16)) fail("Integer is too big to fit in a 8-bit integer: ", i16);
return i8;
}
#ifdef __GNUC__
diff --git a/src/stdlib/lists.c b/src/stdlib/lists.c
index ce27f822..415e28a5 100644
--- a/src/stdlib/lists.c
+++ b/src/stdlib/lists.c
@@ -6,8 +6,8 @@
#include <stdint.h>
#include <sys/param.h>
-#include "lists.h"
#include "integers.h"
+#include "lists.h"
#include "math.h"
#include "metamethods.h"
#include "optionals.h"
@@ -18,39 +18,37 @@
// Use inline version of siphash code:
#include "siphash-internals.h"
-PUREFUNC static INLINE int64_t get_padded_item_size(const TypeInfo_t *info)
-{
+PUREFUNC static INLINE int64_t get_padded_item_size(const TypeInfo_t *info) {
int64_t size = info->ListInfo.item->size;
- if (info->ListInfo.item->align > 1 && size % info->ListInfo.item->align)
- errx(1, "Item size is not padded!");
+ if (info->ListInfo.item->align > 1 && size % info->ListInfo.item->align) errx(1, "Item size is not padded!");
return size;
}
// Replace the list's .data pointer with a new pointer to a copy of the
// data that is compacted and has a stride of exactly `padded_item_size`
-public void List$compact(List_t *list, int64_t padded_item_size)
-{
+public
+void List$compact(List_t *list, int64_t padded_item_size) {
void *copy = NULL;
if (list->length > 0) {
copy = list->atomic ? GC_MALLOC_ATOMIC((size_t)list->length * (size_t)padded_item_size)
- : GC_MALLOC((size_t)list->length * (size_t)padded_item_size);
+ : GC_MALLOC((size_t)list->length * (size_t)padded_item_size);
if ((int64_t)list->stride == padded_item_size) {
memcpy(copy, list->data, (size_t)list->length * (size_t)padded_item_size);
} else {
for (int64_t i = 0; i < list->length; i++)
- memcpy(copy + i*padded_item_size, list->data + list->stride*i, (size_t)padded_item_size);
+ memcpy(copy + i * padded_item_size, list->data + list->stride * i, (size_t)padded_item_size);
}
}
*list = (List_t){
- .data=copy,
- .length=list->length,
- .stride=padded_item_size,
- .atomic=list->atomic,
+ .data = copy,
+ .length = list->length,
+ .stride = padded_item_size,
+ .atomic = list->atomic,
};
}
-public void List$insert(List_t *list, const void *item, Int_t int_index, int64_t padded_item_size)
-{
+public
+void List$insert(List_t *list, const void *item, Int_t int_index, int64_t padded_item_size) {
int64_t index = Int64$from_int(int_index, false);
if (index <= 0) index = list->length + index + 1;
@@ -61,42 +59,38 @@ public void List$insert(List_t *list, const void *item, Int_t int_index, int64_t
if (!list->data) {
list->free = 4;
list->data = list->atomic ? GC_MALLOC_ATOMIC((size_t)list->free * (size_t)padded_item_size)
- : GC_MALLOC((size_t)list->free * (size_t)padded_item_size);
+ : GC_MALLOC((size_t)list->free * (size_t)padded_item_size);
list->stride = padded_item_size;
} else if (list->free < 1 || list->data_refcount != 0 || (int64_t)list->stride != padded_item_size) {
// Resize policy: +50% growth (clamped between 8 and LIST_MAX_FREE_ENTRIES)
- list->free = MIN(LIST_MAX_FREE_ENTRIES, MAX(8, list->length)/2);
+ list->free = MIN(LIST_MAX_FREE_ENTRIES, MAX(8, list->length) / 2);
void *copy = list->atomic ? GC_MALLOC_ATOMIC((size_t)(list->length + list->free) * (size_t)padded_item_size)
- : GC_MALLOC((size_t)(list->length + list->free) * (size_t)padded_item_size);
- for (int64_t i = 0; i < index-1; i++)
- memcpy(copy + i*padded_item_size, list->data + list->stride*i, (size_t)padded_item_size);
- for (int64_t i = index-1; i < (int64_t)list->length; i++)
- memcpy(copy + (i+1)*padded_item_size, list->data + list->stride*i, (size_t)padded_item_size);
+ : GC_MALLOC((size_t)(list->length + list->free) * (size_t)padded_item_size);
+ for (int64_t i = 0; i < index - 1; i++)
+ memcpy(copy + i * padded_item_size, list->data + list->stride * i, (size_t)padded_item_size);
+ for (int64_t i = index - 1; i < (int64_t)list->length; i++)
+ memcpy(copy + (i + 1) * padded_item_size, list->data + list->stride * i, (size_t)padded_item_size);
list->data = copy;
list->data_refcount = 0;
list->stride = padded_item_size;
} else {
- if (index != list->length+1) {
+ if (index != list->length + 1) {
assert(list->length >= index);
- size_t size = (size_t)((list->length - index + 1)*padded_item_size);
+ size_t size = (size_t)((list->length - index + 1) * padded_item_size);
assert(size < SIZE_MAX);
- memmove(
- list->data + index*padded_item_size,
- list->data + (index-1)*padded_item_size,
- size);
+ memmove(list->data + index * padded_item_size, list->data + (index - 1) * padded_item_size, size);
}
}
assert(list->free > 0);
--list->free;
++list->length;
- memcpy((void*)list->data + (index-1)*padded_item_size, item, (size_t)padded_item_size);
+ memcpy((void *)list->data + (index - 1) * padded_item_size, item, (size_t)padded_item_size);
}
-public void List$insert_all(List_t *list, List_t to_insert, Int_t int_index, int64_t padded_item_size)
-{
+public
+void List$insert_all(List_t *list, List_t to_insert, Int_t int_index, int64_t padded_item_size) {
int64_t index = Int64$from_int(int_index, false);
- if (to_insert.length == 0)
- return;
+ if (to_insert.length == 0) return;
if (!list->data) {
*list = to_insert;
@@ -111,34 +105,33 @@ public void List$insert_all(List_t *list, List_t to_insert, Int_t int_index, int
fail("Invalid insertion index ", index, " for a list with length ", (int64_t)list->length);
if ((int64_t)list->free >= (int64_t)to_insert.length // Adequate free space
- && list->data_refcount == 0 // Not aliased memory
- && (int64_t)list->stride == padded_item_size) { // Contiguous list
+ && list->data_refcount == 0 // Not aliased memory
+ && (int64_t)list->stride == padded_item_size) { // Contiguous list
// If we can fit this within the list's preallocated free space, do that:
list->free -= to_insert.length;
list->length += to_insert.length;
- if (index != list->length+1)
- memmove((void*)list->data + index*padded_item_size,
- list->data + (index-1)*padded_item_size,
- (size_t)((list->length - index + to_insert.length-1)*padded_item_size));
+ if (index != list->length + 1)
+ memmove((void *)list->data + index * padded_item_size, list->data + (index - 1) * padded_item_size,
+ (size_t)((list->length - index + to_insert.length - 1) * padded_item_size));
for (int64_t i = 0; i < to_insert.length; i++)
- memcpy((void*)list->data + (index-1 + i)*padded_item_size,
- to_insert.data + i*to_insert.stride, (size_t)padded_item_size);
+ memcpy((void *)list->data + (index - 1 + i) * padded_item_size, to_insert.data + i * to_insert.stride,
+ (size_t)padded_item_size);
} else {
// Otherwise, allocate a new chunk of memory for the list and populate it:
int64_t new_len = list->length + to_insert.length;
- list->free = MIN(LIST_MAX_FREE_ENTRIES, MAX(8, new_len/4));
+ list->free = MIN(LIST_MAX_FREE_ENTRIES, MAX(8, new_len / 4));
void *data = list->atomic ? GC_MALLOC_ATOMIC((size_t)((new_len + list->free) * padded_item_size))
- : GC_MALLOC((size_t)((new_len + list->free) * padded_item_size));
+ : GC_MALLOC((size_t)((new_len + list->free) * padded_item_size));
void *p = data;
// Copy first chunk of `list` if needed:
if (index > 1) {
if (list->stride == padded_item_size) {
- memcpy(p, list->data, (size_t)((index-1)*padded_item_size));
- p += (index-1)*padded_item_size;
+ memcpy(p, list->data, (size_t)((index - 1) * padded_item_size));
+ p += (index - 1) * padded_item_size;
} else {
- for (int64_t i = 0; i < index-1; i++) {
- memcpy(p, list->data + list->stride*i, (size_t)padded_item_size);
+ for (int64_t i = 0; i < index - 1; i++) {
+ memcpy(p, list->data + list->stride * i, (size_t)padded_item_size);
p += padded_item_size;
}
}
@@ -146,11 +139,11 @@ public void List$insert_all(List_t *list, List_t to_insert, Int_t int_index, int
// Copy `to_insert`
if (to_insert.stride == padded_item_size) {
- memcpy(p, to_insert.data, (size_t)(to_insert.length*padded_item_size));
- p += to_insert.length*padded_item_size;
+ memcpy(p, to_insert.data, (size_t)(to_insert.length * padded_item_size));
+ p += to_insert.length * padded_item_size;
} else {
- for (int64_t i = 0; i < index-1; i++) {
- memcpy(p, to_insert.data + to_insert.stride*i, (size_t)padded_item_size);
+ for (int64_t i = 0; i < index - 1; i++) {
+ memcpy(p, to_insert.data + to_insert.stride * i, (size_t)padded_item_size);
p += padded_item_size;
}
}
@@ -158,11 +151,12 @@ public void List$insert_all(List_t *list, List_t to_insert, Int_t int_index, int
// Copy last chunk of `list` if needed:
if (index < list->length + 1) {
if (list->stride == padded_item_size) {
- memcpy(p, list->data + padded_item_size*(index-1), (size_t)((list->length - index + 1)*padded_item_size));
- p += (list->length - index + 1)*padded_item_size;
+ memcpy(p, list->data + padded_item_size * (index - 1),
+ (size_t)((list->length - index + 1) * padded_item_size));
+ p += (list->length - index + 1) * padded_item_size;
} else {
- for (int64_t i = index-1; i < list->length-1; i++) {
- memcpy(p, list->data + list->stride*i, (size_t)padded_item_size);
+ for (int64_t i = index - 1; i < list->length - 1; i++) {
+ memcpy(p, list->data + list->stride * i, (size_t)padded_item_size);
p += padded_item_size;
}
}
@@ -174,27 +168,27 @@ public void List$insert_all(List_t *list, List_t to_insert, Int_t int_index, int
}
}
-public void List$remove_at(List_t *list, Int_t int_index, Int_t int_count, int64_t padded_item_size)
-{
+public
+void List$remove_at(List_t *list, Int_t int_index, Int_t int_count, int64_t padded_item_size) {
int64_t index = Int64$from_int(int_index, false);
if (index < 1) index = list->length + index + 1;
int64_t count = Int64$from_int(int_count, false);
if (index < 1 || index > (int64_t)list->length || count < 1) return;
- if (count > list->length - index + 1)
- count = (list->length - index) + 1;
+ if (count > list->length - index + 1) count = (list->length - index) + 1;
if (index == 1) {
list->data += list->stride * count;
} else if (index + count > list->length) {
list->free += count;
} else if (list->data_refcount != 0 || (int64_t)list->stride != padded_item_size) {
- void *copy = list->atomic ? GC_MALLOC_ATOMIC((size_t)((list->length-1) * padded_item_size))
- : GC_MALLOC((size_t)((list->length-1) * padded_item_size));
+ void *copy = list->atomic ? GC_MALLOC_ATOMIC((size_t)((list->length - 1) * padded_item_size))
+ : GC_MALLOC((size_t)((list->length - 1) * padded_item_size));
for (int64_t src = 1, dest = 1; src <= (int64_t)list->length; src++) {
if (src < index || src >= index + count) {
- memcpy(copy + (dest - 1)*padded_item_size, list->data + list->stride*(src - 1), (size_t)padded_item_size);
+ memcpy(copy + (dest - 1) * padded_item_size, list->data + list->stride * (src - 1),
+ (size_t)padded_item_size);
++dest;
}
}
@@ -202,26 +196,27 @@ public void List$remove_at(List_t *list, Int_t int_index, Int_t int_count, int64
list->free = 0;
list->data_refcount = 0;
} else {
- memmove((void*)list->data + (index-1)*padded_item_size, list->data + (index-1 + count)*padded_item_size,
- (size_t)((list->length - index + count - 1)*padded_item_size));
+ memmove((void *)list->data + (index - 1) * padded_item_size,
+ list->data + (index - 1 + count) * padded_item_size,
+ (size_t)((list->length - index + count - 1) * padded_item_size));
list->free += count;
}
list->length -= count;
if (list->length == 0) list->data = NULL;
}
-public void List$remove_item(List_t *list, void *item, Int_t max_removals, const TypeInfo_t *type)
-{
+public
+void List$remove_item(List_t *list, void *item, Int_t max_removals, const TypeInfo_t *type) {
int64_t padded_item_size = get_padded_item_size(type);
- const Int_t ZERO = (Int_t){.small=(0<<2)|1};
- const Int_t ONE = (Int_t){.small=(1<<2)|1};
+ const Int_t ZERO = (Int_t){.small = (0 << 2) | 1};
+ const Int_t ONE = (Int_t){.small = (1 << 2) | 1};
const TypeInfo_t *item_type = type->ListInfo.item;
- for (int64_t i = 0; i < list->length; ) {
+ for (int64_t i = 0; i < list->length;) {
if (max_removals.small == ZERO.small) // zero
break;
- if (generic_equal(item, list->data + i*list->stride, item_type)) {
- List$remove_at(list, I(i+1), ONE, padded_item_size);
+ if (generic_equal(item, list->data + i * list->stride, item_type)) {
+ List$remove_at(list, I(i + 1), ONE, padded_item_size);
max_removals = Int$minus(max_removals, ONE);
} else {
i++;
@@ -229,45 +224,41 @@ public void List$remove_item(List_t *list, void *item, Int_t max_removals, const
}
}
-public OptionalInt_t List$find(List_t list, void *item, const TypeInfo_t *type)
-{
+public
+OptionalInt_t List$find(List_t list, void *item, const TypeInfo_t *type) {
const TypeInfo_t *item_type = type->ListInfo.item;
for (int64_t i = 0; i < list.length; i++) {
- if (generic_equal(item, list.data + i*list.stride, item_type))
- return I(i+1);
+ if (generic_equal(item, list.data + i * list.stride, item_type)) return I(i + 1);
}
return NONE_INT;
}
-public OptionalInt_t List$first(List_t list, Closure_t predicate)
-{
- bool (*is_good)(void*, void*) = (void*)predicate.fn;
+public
+OptionalInt_t List$first(List_t list, Closure_t predicate) {
+ bool (*is_good)(void *, void *) = (void *)predicate.fn;
for (int64_t i = 0; i < list.length; i++) {
- if (is_good(list.data + i*list.stride, predicate.userdata))
- return I(i+1);
+ if (is_good(list.data + i * list.stride, predicate.userdata)) return I(i + 1);
}
return NONE_INT;
}
-static Closure_t _sort_comparison = {.fn=NULL};
+static Closure_t _sort_comparison = {.fn = NULL};
-int _compare_closure(const void *a, const void *b)
-{
- typedef int (*comparison_t)(const void*, const void*, void*);
+int _compare_closure(const void *a, const void *b) {
+ typedef int (*comparison_t)(const void *, const void *, void *);
return ((comparison_t)_sort_comparison.fn)(a, b, _sort_comparison.userdata);
}
-public void List$sort(List_t *list, Closure_t comparison, int64_t padded_item_size)
-{
- if (list->data_refcount != 0 || (int64_t)list->stride != padded_item_size)
- List$compact(list, padded_item_size);
+public
+void List$sort(List_t *list, Closure_t comparison, int64_t padded_item_size) {
+ if (list->data_refcount != 0 || (int64_t)list->stride != padded_item_size) List$compact(list, padded_item_size);
_sort_comparison = comparison;
qsort(list->data, (size_t)list->length, (size_t)padded_item_size, _compare_closure);
}
-public List_t List$sorted(List_t list, Closure_t comparison, int64_t padded_item_size)
-{
+public
+List_t List$sorted(List_t list, Closure_t comparison, int64_t padded_item_size) {
List$compact(&list, padded_item_size);
_sort_comparison = comparison;
qsort(list.data, (size_t)list.length, (size_t)padded_item_size, _compare_closure);
@@ -283,13 +274,12 @@ static ssize_t getrandom(void *buf, size_t buflen, unsigned int flags) {
}
#elif defined(__linux__)
// Use getrandom()
-# include <sys/random.h>
+#include <sys/random.h>
#else
- #error "Unsupported platform for secure random number generation"
+#error "Unsupported platform for secure random number generation"
#endif
-static int64_t _default_random_int64(int64_t min, int64_t max, void *userdata)
-{
+static int64_t _default_random_int64(int64_t min, int64_t max, void *userdata) {
(void)userdata;
if (min > max) fail("Random minimum value (", min, ") is larger than the maximum value (", max, ")");
if (min == max) return min;
@@ -303,50 +293,49 @@ static int64_t _default_random_int64(int64_t min, int64_t max, void *userdata)
return (int64_t)((uint64_t)min + (r % range));
}
-public void List$shuffle(List_t *list, OptionalClosure_t random_int64, int64_t padded_item_size)
-{
- if (list->data_refcount != 0 || (int64_t)list->stride != padded_item_size)
- List$compact(list, padded_item_size);
+public
+void List$shuffle(List_t *list, OptionalClosure_t random_int64, int64_t padded_item_size) {
+ if (list->data_refcount != 0 || (int64_t)list->stride != padded_item_size) List$compact(list, padded_item_size);
- typedef int64_t (*rng_fn_t)(int64_t, int64_t, void*);
+ typedef int64_t (*rng_fn_t)(int64_t, int64_t, void *);
rng_fn_t rng_fn = random_int64.fn ? (rng_fn_t)random_int64.fn : _default_random_int64;
char tmp[padded_item_size];
- for (int64_t i = list->length-1; i > 1; i--) {
+ for (int64_t i = list->length - 1; i > 1; i--) {
int64_t j = rng_fn(0, i, random_int64.userdata);
- if unlikely (j < 0 || j > list->length-1)
+ if unlikely (j < 0 || j > list->length - 1)
fail("The provided random number function returned an invalid value: ", j, " (not between 0 and ", i, ")");
- memcpy(tmp, list->data + i*padded_item_size, (size_t)padded_item_size);
- memcpy((void*)list->data + i*padded_item_size, list->data + j*padded_item_size, (size_t)padded_item_size);
- memcpy((void*)list->data + j*padded_item_size, tmp, (size_t)padded_item_size);
+ memcpy(tmp, list->data + i * padded_item_size, (size_t)padded_item_size);
+ memcpy((void *)list->data + i * padded_item_size, list->data + j * padded_item_size, (size_t)padded_item_size);
+ memcpy((void *)list->data + j * padded_item_size, tmp, (size_t)padded_item_size);
}
}
-public List_t List$shuffled(List_t list, Closure_t random_int64, int64_t padded_item_size)
-{
+public
+List_t List$shuffled(List_t list, Closure_t random_int64, int64_t padded_item_size) {
List$compact(&list, padded_item_size);
List$shuffle(&list, random_int64, padded_item_size);
return list;
}
-public void *List$random(List_t list, OptionalClosure_t random_int64)
-{
- if (list.length == 0)
- return NULL; // fail("Cannot get a random item from an empty list!");
+public
+void *List$random(List_t list, OptionalClosure_t random_int64) {
+ if (list.length == 0) return NULL; // fail("Cannot get a random item from an empty list!");
- typedef int64_t (*rng_fn_t)(int64_t, int64_t, void*);
+ typedef int64_t (*rng_fn_t)(int64_t, int64_t, void *);
rng_fn_t rng_fn = random_int64.fn ? (rng_fn_t)random_int64.fn : _default_random_int64;
- int64_t index = rng_fn(0, list.length-1, random_int64.userdata);
- if unlikely (index < 0 || index > list.length-1)
- fail("The provided random number function returned an invalid value: ", index, " (not between 0 and ", (int64_t)list.length, ")");
- return list.data + list.stride*index;
+ int64_t index = rng_fn(0, list.length - 1, random_int64.userdata);
+ if unlikely (index < 0 || index > list.length - 1)
+ fail("The provided random number function returned an invalid value: ", index, " (not between 0 and ",
+ (int64_t)list.length, ")");
+ return list.data + list.stride * index;
}
-public Table_t List$counts(List_t list, const TypeInfo_t *type)
-{
+public
+Table_t List$counts(List_t list, const TypeInfo_t *type) {
Table_t counts = {};
const TypeInfo_t count_type = *Table$info(type->ListInfo.item, &Int$info);
for (int64_t i = 0; i < list.length; i++) {
- void *key = list.data + i*list.stride;
+ void *key = list.data + i * list.stride;
int64_t *count = Table$get(counts, key, &count_type);
int64_t val = count ? *count + 1 : 1;
Table$set(&counts, key, &val, &count_type);
@@ -354,14 +343,13 @@ public Table_t List$counts(List_t list, const TypeInfo_t *type)
return counts;
}
-static double _default_random_num(void *userdata)
-{
+static double _default_random_num(void *userdata) {
(void)userdata;
union {
Num_t num;
uint64_t bits;
- } r = {.bits=0}, one = {.num=1.0};
- assert(getrandom((uint8_t*)&r, sizeof(r), 0) == sizeof(r));
+ } r = {.bits = 0}, one = {.num = 1.0};
+ assert(getrandom((uint8_t *)&r, sizeof(r), 0) == sizeof(r));
// Set r.num to 1.<random-bits>
r.bits &= ~(0xFFFULL << 52);
@@ -369,39 +357,30 @@ static double _default_random_num(void *userdata)
return r.num - 1.0;
}
-public List_t List$sample(List_t list, Int_t int_n, List_t weights, OptionalClosure_t random_num, int64_t padded_item_size)
-{
+public
+List_t List$sample(List_t list, Int_t int_n, List_t weights, OptionalClosure_t random_num, int64_t padded_item_size) {
int64_t n = Int64$from_int(int_n, false);
- if (n < 0)
- fail("Cannot select a negative number of values");
+ if (n < 0) fail("Cannot select a negative number of values");
- if (n == 0)
- return (List_t){};
+ if (n == 0) return (List_t){};
- if (list.length == 0)
- fail("There are no elements in this list!");
+ if (list.length == 0) fail("There are no elements in this list!");
if (weights.length != list.length)
fail("List has ", (int64_t)list.length, " elements, but there are ", (int64_t)weights.length, " weights given");
double total = 0.0;
for (int64_t i = 0; i < weights.length && i < list.length; i++) {
- double weight = *(double*)(weights.data + weights.stride*i);
- if (isinf(weight))
- fail("Infinite weight!");
- else if (isnan(weight))
- fail("NaN weight!");
- else if (weight < 0.0)
- fail("Negative weight!");
- else
- total += weight;
+ double weight = *(double *)(weights.data + weights.stride * i);
+ if (isinf(weight)) fail("Infinite weight!");
+ else if (isnan(weight)) fail("NaN weight!");
+ else if (weight < 0.0) fail("Negative weight!");
+ else total += weight;
}
- if (isinf(total))
- fail("Sample weights have overflowed to infinity");
+ if (isinf(total)) fail("Sample weights have overflowed to infinity");
- if (total == 0.0)
- fail("None of the given weights are nonzero");
+ if (total == 0.0) fail("None of the given weights are nonzero");
double inverse_average = (double)list.length / total;
@@ -411,7 +390,7 @@ public List_t List$sample(List_t list, Int_t int_n, List_t weights, OptionalClos
} aliases[list.length];
for (int64_t i = 0; i < list.length; i++) {
- double weight = i >= weights.length ? 0.0 : *(double*)(weights.data + weights.stride*i);
+ double weight = i >= weights.length ? 0.0 : *(double *)(weights.data + weights.stride * i);
aliases[i].odds = weight * inverse_average;
aliases[i].alias = -1;
}
@@ -435,16 +414,16 @@ public List_t List$sample(List_t list, Int_t int_n, List_t weights, OptionalClos
}
for (int64_t i = small; i < list.length; i++)
- if (aliases[i].alias == -1)
- aliases[i].alias = i;
+ if (aliases[i].alias == -1) aliases[i].alias = i;
- typedef double (*rng_fn_t)(void*);
+ typedef double (*rng_fn_t)(void *);
rng_fn_t rng_fn = random_num.fn ? (rng_fn_t)random_num.fn : _default_random_num;
- List_t selected = {
- .data=list.atomic ? GC_MALLOC_ATOMIC((size_t)(n * padded_item_size)) : GC_MALLOC((size_t)(n * padded_item_size)),
- .length=n,
- .stride=padded_item_size, .atomic=list.atomic};
+ List_t selected = {.data = list.atomic ? GC_MALLOC_ATOMIC((size_t)(n * padded_item_size))
+ : GC_MALLOC((size_t)(n * padded_item_size)),
+ .length = n,
+ .stride = padded_item_size,
+ .atomic = list.atomic};
for (int64_t i = 0; i < n; i++) {
double r = rng_fn(random_num.userdata);
if unlikely (r < 0.0 || r >= 1.0)
@@ -452,85 +431,77 @@ public List_t List$sample(List_t list, Int_t int_n, List_t weights, OptionalClos
r *= (double)list.length;
int64_t index = (int64_t)r;
assert(index >= 0 && index < list.length);
- if ((r - (double)index) > aliases[index].odds)
- index = aliases[index].alias;
- memcpy(selected.data + i*selected.stride, list.data + index*list.stride, (size_t)padded_item_size);
+ if ((r - (double)index) > aliases[index].odds) index = aliases[index].alias;
+ memcpy(selected.data + i * selected.stride, list.data + index * list.stride, (size_t)padded_item_size);
}
return selected;
}
-public List_t List$from(List_t list, Int_t first)
-{
- return List$slice(list, first, I_small(-1));
-}
+public
+List_t List$from(List_t list, Int_t first) { return List$slice(list, first, I_small(-1)); }
-public List_t List$to(List_t list, Int_t last)
-{
- return List$slice(list, I_small(1), last);
-}
+public
+List_t List$to(List_t list, Int_t last) { return List$slice(list, I_small(1), last); }
-public List_t List$by(List_t list, Int_t int_stride, int64_t padded_item_size)
-{
+public
+List_t List$by(List_t list, Int_t int_stride, int64_t padded_item_size) {
int64_t stride = Int64$from_int(int_stride, false);
// In the unlikely event that the stride value would be too large to fit in
// a 15-bit integer, fall back to creating a copy of the list:
- if (unlikely(list.stride*stride < LIST_MIN_STRIDE || list.stride*stride > LIST_MAX_STRIDE)) {
+ if (unlikely(list.stride * stride < LIST_MIN_STRIDE || list.stride * stride > LIST_MAX_STRIDE)) {
void *copy = NULL;
int64_t len = (stride < 0 ? list.length / -stride : list.length / stride) + ((list.length % stride) != 0);
if (len > 0) {
- copy = list.atomic ? GC_MALLOC_ATOMIC((size_t)(len * padded_item_size)) : GC_MALLOC((size_t)(len * padded_item_size));
+ copy = list.atomic ? GC_MALLOC_ATOMIC((size_t)(len * padded_item_size))
+ : GC_MALLOC((size_t)(len * padded_item_size));
void *start = (stride < 0 ? list.data + (list.stride * (list.length - 1)) : list.data);
for (int64_t i = 0; i < len; i++)
- memcpy(copy + i*padded_item_size, start + list.stride*stride*i, (size_t)padded_item_size);
+ memcpy(copy + i * padded_item_size, start + list.stride * stride * i, (size_t)padded_item_size);
}
return (List_t){
- .data=copy,
- .length=len,
- .stride=padded_item_size,
- .atomic=list.atomic,
+ .data = copy,
+ .length = len,
+ .stride = padded_item_size,
+ .atomic = list.atomic,
};
}
- if (stride == 0)
- return (List_t){.atomic=list.atomic};
+ if (stride == 0) return (List_t){.atomic = list.atomic};
return (List_t){
- .atomic=list.atomic,
- .data=(stride < 0 ? list.data + (list.stride * (list.length - 1)) : list.data),
- .length=(stride < 0 ? list.length / -stride : list.length / stride) + ((list.length % stride) != 0),
- .stride=list.stride * stride,
- .data_refcount=list.data_refcount,
+ .atomic = list.atomic,
+ .data = (stride < 0 ? list.data + (list.stride * (list.length - 1)) : list.data),
+ .length = (stride < 0 ? list.length / -stride : list.length / stride) + ((list.length % stride) != 0),
+ .stride = list.stride * stride,
+ .data_refcount = list.data_refcount,
};
}
-public List_t List$slice(List_t list, Int_t int_first, Int_t int_last)
+public
+List_t List$slice(List_t list, Int_t int_first, Int_t int_last)
{
int64_t first = Int64$from_int(int_first, false);
- if (first < 0)
- first = list.length + first + 1;
+ if (first < 0) first = list.length + first + 1;
int64_t last = Int64$from_int(int_last, false);
- if (last < 0)
- last = list.length + last + 1;
+ if (last < 0) last = list.length + last + 1;
- if (last > list.length)
- last = list.length;
+ if (last > list.length) last = list.length;
- if (first < 1 || first > list.length || last == 0)
- return (List_t){.atomic=list.atomic};
+ if (first < 1 || first > list.length || last == 0) return (List_t){.atomic = list.atomic};
return (List_t){
- .atomic=list.atomic,
- .data=list.data + list.stride*(first-1),
- .length=last - first + 1,
- .stride=list.stride,
- .data_refcount=list.data_refcount,
+ .atomic = list.atomic,
+ .data = list.data + list.stride * (first - 1),
+ .length = last - first + 1,
+ .stride = list.stride,
+ .data_refcount = list.data_refcount,
};
}
-public List_t List$reversed(List_t list, int64_t padded_item_size)
-{
+public
+List_t List$reversed(List_t list, int64_t padded_item_size) {
// Just in case negating the stride gives a value that doesn't fit into a
// 15-bit integer, fall back to List$by()'s more general method of copying
// the list. This should only happen if list.stride is MIN_STRIDE to
@@ -540,58 +511,54 @@ public List_t List$reversed(List_t list, int64_t padded_item_size)
List_t reversed = list;
reversed.stride = -list.stride;
- reversed.data = list.data + (list.length-1)*list.stride;
+ reversed.data = list.data + (list.length - 1) * list.stride;
return reversed;
}
-public List_t List$concat(List_t x, List_t y, int64_t padded_item_size)
-{
- void *data = x.atomic ? GC_MALLOC_ATOMIC((size_t)(padded_item_size*(x.length + y.length)))
- : GC_MALLOC((size_t)(padded_item_size*(x.length + y.length)));
+public
+List_t List$concat(List_t x, List_t y, int64_t padded_item_size) {
+ void *data = x.atomic ? GC_MALLOC_ATOMIC((size_t)(padded_item_size * (x.length + y.length)))
+ : GC_MALLOC((size_t)(padded_item_size * (x.length + y.length)));
if (x.stride == padded_item_size) {
- memcpy(data, x.data, (size_t)(padded_item_size*x.length));
+ memcpy(data, x.data, (size_t)(padded_item_size * x.length));
} else {
for (int64_t i = 0; i < x.length; i++)
- memcpy(data + i*padded_item_size, x.data + i*padded_item_size, (size_t)padded_item_size);
+ memcpy(data + i * padded_item_size, x.data + i * padded_item_size, (size_t)padded_item_size);
}
- void *dest = data + padded_item_size*x.length;
+ void *dest = data + padded_item_size * x.length;
if (y.stride == padded_item_size) {
- memcpy(dest, y.data, (size_t)(padded_item_size*y.length));
+ memcpy(dest, y.data, (size_t)(padded_item_size * y.length));
} else {
for (int64_t i = 0; i < y.length; i++)
- memcpy(dest + i*padded_item_size, y.data + i*y.stride, (size_t)padded_item_size);
+ memcpy(dest + i * padded_item_size, y.data + i * y.stride, (size_t)padded_item_size);
}
return (List_t){
- .data=data,
- .length=x.length + y.length,
- .stride=padded_item_size,
- .atomic=x.atomic,
+ .data = data,
+ .length = x.length + y.length,
+ .stride = padded_item_size,
+ .atomic = x.atomic,
};
}
-public bool List$has(List_t list, void *item, const TypeInfo_t *type)
-{
+public
+bool List$has(List_t list, void *item, const TypeInfo_t *type) {
const TypeInfo_t *item_type = type->ListInfo.item;
for (int64_t i = 0; i < list.length; i++) {
- if (generic_equal(list.data + i*list.stride, item, item_type))
- return true;
+ if (generic_equal(list.data + i * list.stride, item, item_type)) return true;
}
return false;
}
-public void List$clear(List_t *list)
-{
- *list = (List_t){.data=0, .length=0};
-}
+public
+void List$clear(List_t *list) { *list = (List_t){.data = 0, .length = 0}; }
-public int32_t List$compare(const void *vx, const void *vy, const TypeInfo_t *type)
-{
- const List_t *x = (List_t*)vx, *y = (List_t*)vy;
+public
+int32_t List$compare(const void *vx, const void *vy, const TypeInfo_t *type) {
+ const List_t *x = (List_t *)vx, *y = (List_t *)vy;
// Early out for lists with the same data, e.g. two copies of the same list:
- if (x->data == y->data && x->stride == y->stride)
- return (x->length > y->length) - (x->length < y->length);
+ if (x->data == y->data && x->stride == y->stride) return (x->length > y->length) - (x->length < y->length);
const TypeInfo_t *item = type->ListInfo.item;
if (item->tag == PointerInfo || !item->metamethods.compare) { // data comparison
@@ -599,128 +566,120 @@ public int32_t List$compare(const void *vx, const void *vy, const TypeInfo_t *ty
if (type->ListInfo.item->align > 1 && item_padded_size % type->ListInfo.item->align)
errx(1, "Item size is not padded!");
- if ((int64_t)x->stride == item_padded_size && (int64_t)y->stride == item_padded_size && item->size == item_padded_size) {
- int32_t cmp = (int32_t)memcmp(x->data, y->data, (size_t)(MIN(x->length, y->length)*item_padded_size));
+ if ((int64_t)x->stride == item_padded_size && (int64_t)y->stride == item_padded_size
+ && item->size == item_padded_size) {
+ int32_t cmp = (int32_t)memcmp(x->data, y->data, (size_t)(MIN(x->length, y->length) * item_padded_size));
if (cmp != 0) return cmp;
} else {
for (int32_t i = 0, len = MIN(x->length, y->length); i < len; i++) {
- int32_t cmp = (int32_t)memcmp(x->data+ x->stride*i, y->data + y->stride*i, (size_t)(item->size));
+ int32_t cmp = (int32_t)memcmp(x->data + x->stride * i, y->data + y->stride * i, (size_t)(item->size));
if (cmp != 0) return cmp;
}
}
} else {
for (int32_t i = 0, len = MIN(x->length, y->length); i < len; i++) {
- int32_t cmp = generic_compare(x->data + x->stride*i, y->data + y->stride*i, item);
+ int32_t cmp = generic_compare(x->data + x->stride * i, y->data + y->stride * i, item);
if (cmp != 0) return cmp;
}
}
return (x->length > y->length) - (x->length < y->length);
}
-public bool List$equal(const void *x, const void *y, const TypeInfo_t *type)
-{
- return x == y || (((List_t*)x)->length == ((List_t*)y)->length && List$compare(x, y, type) == 0);
+public
+bool List$equal(const void *x, const void *y, const TypeInfo_t *type) {
+ return x == y || (((List_t *)x)->length == ((List_t *)y)->length && List$compare(x, y, type) == 0);
}
-public Text_t List$as_text(const void *obj, bool colorize, const TypeInfo_t *type)
-{
- List_t *list = (List_t*)obj;
- if (!list)
- return Text$concat(Text("["), generic_as_text(NULL, false, type->ListInfo.item), Text("]"));
+public
+Text_t List$as_text(const void *obj, bool colorize, const TypeInfo_t *type) {
+ List_t *list = (List_t *)obj;
+ if (!list) return Text$concat(Text("["), generic_as_text(NULL, false, type->ListInfo.item), Text("]"));
const TypeInfo_t *item_type = type->ListInfo.item;
Text_t text = Text("[");
for (int64_t i = 0; i < list->length; i++) {
- if (i > 0)
- text = Text$concat(text, Text(", "));
- Text_t item_text = generic_as_text(list->data + i*list->stride, colorize, item_type);
+ if (i > 0) text = Text$concat(text, Text(", "));
+ Text_t item_text = generic_as_text(list->data + i * list->stride, colorize, item_type);
text = Text$concat(text, item_text);
}
text = Text$concat(text, Text("]"));
return text;
}
-public uint64_t List$hash(const void *obj, const TypeInfo_t *type)
-{
- const List_t *list = (List_t*)obj;
+public
+uint64_t List$hash(const void *obj, const TypeInfo_t *type) {
+ const List_t *list = (List_t *)obj;
const TypeInfo_t *item = type->ListInfo.item;
siphash sh;
siphashinit(&sh, sizeof(uint64_t[list->length]));
- if (item->tag == PointerInfo || (!item->metamethods.hash && item->size == sizeof(void*))) { // Raw data hash
+ if (item->tag == PointerInfo || (!item->metamethods.hash && item->size == sizeof(void *))) { // Raw data hash
for (int64_t i = 0; i < list->length; i++)
- siphashadd64bits(&sh, (uint64_t)(list->data + i*list->stride));
+ siphashadd64bits(&sh, (uint64_t)(list->data + i * list->stride));
} else {
for (int64_t i = 0; i < list->length; i++) {
- uint64_t item_hash = generic_hash(list->data + i*list->stride, item);
+ uint64_t item_hash = generic_hash(list->data + i * list->stride, item);
siphashadd64bits(&sh, item_hash);
}
}
return siphashfinish_last_part(&sh, 0);
}
-static void siftdown(List_t *heap, int64_t startpos, int64_t pos, Closure_t comparison, int64_t padded_item_size)
-{
+static void siftdown(List_t *heap, int64_t startpos, int64_t pos, Closure_t comparison, int64_t padded_item_size) {
assert(pos > 0 && pos < heap->length);
char newitem[padded_item_size];
- memcpy(newitem, heap->data + heap->stride*pos, (size_t)(padded_item_size));
+ memcpy(newitem, heap->data + heap->stride * pos, (size_t)(padded_item_size));
while (pos > startpos) {
int64_t parentpos = (pos - 1) >> 1;
- typedef int32_t (*cmp_fn_t)(void*, void*, void*);
- int32_t cmp = ((cmp_fn_t)comparison.fn)(newitem, heap->data + heap->stride*parentpos, comparison.userdata);
- if (cmp >= 0)
- break;
+ typedef int32_t (*cmp_fn_t)(void *, void *, void *);
+ int32_t cmp = ((cmp_fn_t)comparison.fn)(newitem, heap->data + heap->stride * parentpos, comparison.userdata);
+ if (cmp >= 0) break;
- memcpy(heap->data + heap->stride*pos, heap->data + heap->stride*parentpos, (size_t)(padded_item_size));
+ memcpy(heap->data + heap->stride * pos, heap->data + heap->stride * parentpos, (size_t)(padded_item_size));
pos = parentpos;
}
- memcpy(heap->data + heap->stride*pos, newitem, (size_t)(padded_item_size));
+ memcpy(heap->data + heap->stride * pos, newitem, (size_t)(padded_item_size));
}
-static void siftup(List_t *heap, int64_t pos, Closure_t comparison, int64_t padded_item_size)
-{
+static void siftup(List_t *heap, int64_t pos, Closure_t comparison, int64_t padded_item_size) {
int64_t endpos = heap->length;
int64_t startpos = pos;
assert(pos < endpos);
char old_top[padded_item_size];
- memcpy(old_top, heap->data + heap->stride*pos, (size_t)(padded_item_size));
+ memcpy(old_top, heap->data + heap->stride * pos, (size_t)(padded_item_size));
// Bubble up the smallest leaf node
int64_t limit = endpos >> 1;
while (pos < limit) {
- int64_t childpos = 2*pos + 1; // Smaller of the two child nodes
+ int64_t childpos = 2 * pos + 1; // Smaller of the two child nodes
if (childpos + 1 < endpos) {
- typedef int32_t (*cmp_fn_t)(void*, void*, void*);
- int32_t cmp = ((cmp_fn_t)comparison.fn)(
- heap->data + heap->stride*childpos,
- heap->data + heap->stride*(childpos + 1),
- comparison.userdata);
+ typedef int32_t (*cmp_fn_t)(void *, void *, void *);
+ int32_t cmp = ((cmp_fn_t)comparison.fn)(heap->data + heap->stride * childpos,
+ heap->data + heap->stride * (childpos + 1), comparison.userdata);
childpos += (cmp >= 0);
}
// Move the child node up:
- memcpy(heap->data + heap->stride*pos, heap->data + heap->stride*childpos, (size_t)(padded_item_size));
+ memcpy(heap->data + heap->stride * pos, heap->data + heap->stride * childpos, (size_t)(padded_item_size));
pos = childpos;
}
- memcpy(heap->data + heap->stride*pos, old_top, (size_t)(padded_item_size));
+ memcpy(heap->data + heap->stride * pos, old_top, (size_t)(padded_item_size));
// Shift the node's parents down:
siftdown(heap, startpos, pos, comparison, padded_item_size);
}
-public void List$heap_push(List_t *heap, const void *item, Closure_t comparison, int64_t padded_item_size)
-{
+public
+void List$heap_push(List_t *heap, const void *item, Closure_t comparison, int64_t padded_item_size) {
List$insert(heap, item, I(0), padded_item_size);
if (heap->length > 1) {
- if (heap->data_refcount != 0)
- List$compact(heap, padded_item_size);
- siftdown(heap, 0, heap->length-1, comparison, padded_item_size);
+ if (heap->data_refcount != 0) List$compact(heap, padded_item_size);
+ siftdown(heap, 0, heap->length - 1, comparison, padded_item_size);
}
}
-public void List$heap_pop(List_t *heap, Closure_t comparison, int64_t padded_item_size)
-{
- if (heap->length == 0)
- fail("Attempt to pop from an empty list");
+public
+void List$heap_pop(List_t *heap, Closure_t comparison, int64_t padded_item_size) {
+ if (heap->length == 0) fail("Attempt to pop from an empty list");
if (heap->length == 1) {
*heap = (List_t){};
@@ -728,96 +687,90 @@ public void List$heap_pop(List_t *heap, Closure_t comparison, int64_t padded_ite
heap->data += heap->stride;
--heap->length;
} else {
- if (heap->data_refcount != 0)
- List$compact(heap, padded_item_size);
- memcpy(heap->data, heap->data + heap->stride*(heap->length-1), (size_t)(padded_item_size));
+ if (heap->data_refcount != 0) List$compact(heap, padded_item_size);
+ memcpy(heap->data, heap->data + heap->stride * (heap->length - 1), (size_t)(padded_item_size));
--heap->length;
siftup(heap, 0, comparison, padded_item_size);
}
}
-public void List$heapify(List_t *heap, Closure_t comparison, int64_t padded_item_size)
-{
- if (heap->data_refcount != 0)
- List$compact(heap, padded_item_size);
+public
+void List$heapify(List_t *heap, Closure_t comparison, int64_t padded_item_size) {
+ if (heap->data_refcount != 0) List$compact(heap, padded_item_size);
// It's necessary to bump the refcount because the user's comparison
// function could do stuff that modifies the heap's data.
LIST_INCREF(*heap);
int64_t i, n = heap->length;
- for (i = (n >> 1) - 1 ; i >= 0 ; i--)
+ for (i = (n >> 1) - 1; i >= 0; i--)
siftup(heap, i, comparison, padded_item_size);
LIST_DECREF(*heap);
}
-public Int_t List$binary_search(List_t list, void *target, Closure_t comparison)
-{
- typedef int32_t (*cmp_fn_t)(void*, void*, void*);
- int64_t lo = 0, hi = list.length-1;
+public
+Int_t List$binary_search(List_t list, void *target, Closure_t comparison) {
+ typedef int32_t (*cmp_fn_t)(void *, void *, void *);
+ int64_t lo = 0, hi = list.length - 1;
while (lo <= hi) {
int64_t mid = (lo + hi) / 2;
- int32_t cmp = ((cmp_fn_t)comparison.fn)(
- list.data + list.stride*mid, target, comparison.userdata);
- if (cmp == 0)
- return I(mid+1);
- else if (cmp < 0)
- lo = mid + 1;
- else if (cmp > 0)
- hi = mid - 1;
+ int32_t cmp = ((cmp_fn_t)comparison.fn)(list.data + list.stride * mid, target, comparison.userdata);
+ if (cmp == 0) return I(mid + 1);
+ else if (cmp < 0) lo = mid + 1;
+ else if (cmp > 0) hi = mid - 1;
}
- return I(lo+1); // Return the index where the target would be inserted
+ return I(lo + 1); // Return the index where the target would be inserted
}
-public PUREFUNC bool List$is_none(const void *obj, const TypeInfo_t *info)
-{
+public
+PUREFUNC bool List$is_none(const void *obj, const TypeInfo_t *info) {
(void)info;
- return ((List_t*)obj)->length < 0;
+ return ((List_t *)obj)->length < 0;
}
-public void List$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type)
-{
- List_t list = *(List_t*)obj;
+public
+void List$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type) {
+ List_t list = *(List_t *)obj;
int64_t len = list.length;
Int64$serialize(&len, out, pointers, &Int64$info);
serialize_fn_t item_serialize = type->ListInfo.item->metamethods.serialize;
if (item_serialize) {
for (int64_t i = 0; i < len; i++)
- item_serialize(list.data + i*list.stride, out, pointers, type->ListInfo.item);
+ item_serialize(list.data + i * list.stride, out, pointers, type->ListInfo.item);
} else if (list.stride == type->ListInfo.item->size) {
fwrite(list.data, (size_t)type->ListInfo.item->size, (size_t)len, out);
} else {
for (int64_t i = 0; i < len; i++)
- fwrite(list.data + i*list.stride, (size_t)type->ListInfo.item->size, 1, out);
+ fwrite(list.data + i * list.stride, (size_t)type->ListInfo.item->size, 1, out);
}
}
-public void List$deserialize(FILE *in, void *obj, List_t *pointers, const TypeInfo_t *type)
-{
+public
+void List$deserialize(FILE *in, void *obj, List_t *pointers, const TypeInfo_t *type) {
int64_t len = -1;
Int64$deserialize(in, &len, pointers, &Int64$info);
int64_t padded_size = type->ListInfo.item->size;
if (type->ListInfo.item->align > 0 && padded_size % type->ListInfo.item->align > 0)
padded_size += type->ListInfo.item->align - (padded_size % type->ListInfo.item->align);
List_t list = {
- .length=len,
- .data=GC_MALLOC((size_t)(len*padded_size)),
- .stride=padded_size,
+ .length = len,
+ .data = GC_MALLOC((size_t)(len * padded_size)),
+ .stride = padded_size,
};
deserialize_fn_t item_deserialize = type->ListInfo.item->metamethods.deserialize;
if (item_deserialize) {
for (int64_t i = 0; i < len; i++)
- item_deserialize(in, list.data + i*list.stride, pointers, type->ListInfo.item);
+ item_deserialize(in, list.data + i * list.stride, pointers, type->ListInfo.item);
} else if (list.stride == type->ListInfo.item->size) {
if (fread(list.data, (size_t)type->ListInfo.item->size, (size_t)len, in) != (size_t)len)
fail("Not enough data in stream to deserialize");
} else {
size_t item_size = (size_t)type->ListInfo.item->size;
for (int64_t i = 0; i < len; i++) {
- if (fread(list.data + i*list.stride, item_size, 1, in) != 1)
+ if (fread(list.data + i * list.stride, item_size, 1, in) != 1)
fail("Not enough data in stream to deserialize");
}
}
- *(List_t*)obj = list;
+ *(List_t *)obj = list;
}
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/stdlib/lists.h b/src/stdlib/lists.h
index a2853e48..afda3d74 100644
--- a/src/stdlib/lists.h
+++ b/src/stdlib/lists.h
@@ -10,88 +10,141 @@
#include "util.h"
// Convert negative indices to back-indexed without branching: index0 = index + (index < 0)*(len+1)) - 1
-#define List_get(item_type, arr_expr, index_expr, start, end) *({ \
- const List_t list = arr_expr; int64_t index = index_expr; \
- int64_t off = index + (index < 0) * (list.length + 1) - 1; \
- if (unlikely(off < 0 || off >= list.length)) \
- fail_source(__SOURCE_FILE__, start, end, "Invalid list index: ", index, " (list has length ", (int64_t)list.length, ")\n"); \
- (item_type*)(list.data + list.stride * off);})
-#define List_get_unchecked(type, x, i) *({ const List_t list = x; int64_t index = i; \
- int64_t off = index + (index < 0) * (list.length + 1) - 1; \
- (type*)(list.data + list.stride * off);})
-#define List_lvalue(item_type, arr_expr, index_expr, start, end) *({ \
- List_t *list = arr_expr; int64_t index = index_expr; \
- int64_t off = index + (index < 0) * (list->length + 1) - 1; \
- if (unlikely(off < 0 || off >= list->length)) \
- fail_source(__SOURCE_FILE__, start, end, "Invalid list index: ", index, " (list has length ", (int64_t)list->length, ")\n"); \
- if (list->data_refcount > 0) \
- List$compact(list, sizeof(item_type)); \
- (item_type*)(list->data + list->stride * off); })
-#define List_lvalue_unchecked(item_type, arr_expr, index_expr) *({ \
- List_t *list = arr_expr; int64_t index = index_expr; \
- int64_t off = index + (index < 0) * (list->length + 1) - 1; \
- if (list->data_refcount > 0) \
- List$compact(list, sizeof(item_type)); \
- (item_type*)(list->data + list->stride * off); })
-#define List_set(item_type, list, index, value, start, end) \
- List_lvalue(item_type, arr_expr, index, start, end) = value
-#define is_atomic(x) _Generic(x, bool: true, int8_t: true, int16_t: true, int32_t: true, int64_t: true, float: true, double: true, default: false)
-#define TypedList(t, ...) ({ t items[] = {__VA_ARGS__}; \
- (List_t){.length=sizeof(items)/sizeof(items[0]), \
- .stride=(int64_t)&items[1] - (int64_t)&items[0], \
- .data=memcpy(GC_MALLOC(sizeof(items)), items, sizeof(items)), \
- .atomic=0, \
- .data_refcount=0}; })
-#define TypedListN(t, N, ...) ({ t items[N] = {__VA_ARGS__}; \
- (List_t){.length=N, \
- .stride=(int64_t)&items[1] - (int64_t)&items[0], \
- .data=memcpy(GC_MALLOC(sizeof(items)), items, sizeof(items)), \
- .atomic=0, \
- .data_refcount=0}; })
-#define List(x, ...) ({ __typeof(x) items[] = {x, __VA_ARGS__}; \
- (List_t){.length=sizeof(items)/sizeof(items[0]), \
- .stride=(int64_t)&items[1] - (int64_t)&items[0], \
- .data=memcpy(is_atomic(x) ? GC_MALLOC_ATOMIC(sizeof(items)) : GC_MALLOC(sizeof(items)), items, sizeof(items)), \
- .atomic=is_atomic(x), \
- .data_refcount=0}; })
+#define List_get(item_type, arr_expr, index_expr, start, end) \
+ *({ \
+ const List_t list = arr_expr; \
+ int64_t index = index_expr; \
+ int64_t off = index + (index < 0) * (list.length + 1) - 1; \
+ if (unlikely(off < 0 || off >= list.length)) \
+ fail_source(__SOURCE_FILE__, start, end, "Invalid list index: ", index, " (list has length ", \
+ (int64_t)list.length, ")\n"); \
+ (item_type *)(list.data + list.stride * off); \
+ })
+#define List_get_unchecked(type, x, i) \
+ *({ \
+ const List_t list = x; \
+ int64_t index = i; \
+ int64_t off = index + (index < 0) * (list.length + 1) - 1; \
+ (type *)(list.data + list.stride * off); \
+ })
+#define List_lvalue(item_type, arr_expr, index_expr, start, end) \
+ *({ \
+ List_t *list = arr_expr; \
+ int64_t index = index_expr; \
+ int64_t off = index + (index < 0) * (list->length + 1) - 1; \
+ if (unlikely(off < 0 || off >= list->length)) \
+ fail_source(__SOURCE_FILE__, start, end, "Invalid list index: ", index, " (list has length ", \
+ (int64_t)list->length, ")\n"); \
+ if (list->data_refcount > 0) List$compact(list, sizeof(item_type)); \
+ (item_type *)(list->data + list->stride * off); \
+ })
+#define List_lvalue_unchecked(item_type, arr_expr, index_expr) \
+ *({ \
+ List_t *list = arr_expr; \
+ int64_t index = index_expr; \
+ int64_t off = index + (index < 0) * (list->length + 1) - 1; \
+ if (list->data_refcount > 0) List$compact(list, sizeof(item_type)); \
+ (item_type *)(list->data + list->stride * off); \
+ })
+#define List_set(item_type, list, index, value, start, end) List_lvalue(item_type, arr_expr, index, start, end) = value
+#define is_atomic(x) \
+ _Generic(x, \
+ bool: true, \
+ int8_t: true, \
+ int16_t: true, \
+ int32_t: true, \
+ int64_t: true, \
+ float: true, \
+ double: true, \
+ default: false)
+#define TypedList(t, ...) \
+ ({ \
+ t items[] = {__VA_ARGS__}; \
+ (List_t){.length = sizeof(items) / sizeof(items[0]), \
+ .stride = (int64_t)&items[1] - (int64_t)&items[0], \
+ .data = memcpy(GC_MALLOC(sizeof(items)), items, sizeof(items)), \
+ .atomic = 0, \
+ .data_refcount = 0}; \
+ })
+#define TypedListN(t, N, ...) \
+ ({ \
+ t items[N] = {__VA_ARGS__}; \
+ (List_t){.length = N, \
+ .stride = (int64_t)&items[1] - (int64_t)&items[0], \
+ .data = memcpy(GC_MALLOC(sizeof(items)), items, sizeof(items)), \
+ .atomic = 0, \
+ .data_refcount = 0}; \
+ })
+#define List(x, ...) \
+ ({ \
+ __typeof(x) items[] = {x, __VA_ARGS__}; \
+ (List_t){.length = sizeof(items) / sizeof(items[0]), \
+ .stride = (int64_t)&items[1] - (int64_t)&items[0], \
+ .data = memcpy(is_atomic(x) ? GC_MALLOC_ATOMIC(sizeof(items)) : GC_MALLOC(sizeof(items)), items, \
+ sizeof(items)), \
+ .atomic = is_atomic(x), \
+ .data_refcount = 0}; \
+ })
// List refcounts use a saturating add, where once it's at the max value, it stays there.
#define LIST_INCREF(list) (list).data_refcount += ((list).data_refcount < LIST_MAX_DATA_REFCOUNT)
#define LIST_DECREF(list) (list).data_refcount -= ((list).data_refcount < LIST_MAX_DATA_REFCOUNT)
-#define LIST_COPY(list) ({ LIST_INCREF(list); list; })
+#define LIST_COPY(list) \
+ ({ \
+ LIST_INCREF(list); \
+ list; \
+ })
-#define List$insert_value(list, item_expr, index, padded_item_size) List$insert(list, (__typeof(item_expr)[1]){item_expr}, index, padded_item_size)
+#define List$insert_value(list, item_expr, index, padded_item_size) \
+ List$insert(list, (__typeof(item_expr)[1]){item_expr}, index, padded_item_size)
void List$insert(List_t *list, const void *item, Int_t index, int64_t padded_item_size);
void List$insert_all(List_t *list, List_t to_insert, Int_t index, int64_t padded_item_size);
void List$remove_at(List_t *list, Int_t index, Int_t count, int64_t padded_item_size);
void List$remove_item(List_t *list, void *item, Int_t max_removals, const TypeInfo_t *type);
-#define List$remove_item_value(list, item_expr, max, type) List$remove_item(list, (__typeof(item_expr)[1]){item_expr}, max, type)
+#define List$remove_item_value(list, item_expr, max, type) \
+ List$remove_item(list, (__typeof(item_expr)[1]){item_expr}, max, type)
-#define List$pop(arr_expr, index_expr, item_type, nonnone_var, nonnone_expr, none_expr) ({ \
- List_t *list = arr_expr; \
- Int_t index = index_expr; \
- int64_t index64 = Int64$from_int(index, false); \
- int64_t off = index64 + (index64 < 0) * (list->length + 1) - 1; \
- (off >= 0 && off < list->length) ? ({ \
- item_type nonnone_var = *(item_type*)(list->data + off*list->stride); \
- List$remove_at(list, index, I_small(1), sizeof(item_type)); \
- nonnone_expr; \
- }) : none_expr; })
+#define List$pop(arr_expr, index_expr, item_type, nonnone_var, nonnone_expr, none_expr) \
+ ({ \
+ List_t *list = arr_expr; \
+ Int_t index = index_expr; \
+ int64_t index64 = Int64$from_int(index, false); \
+ int64_t off = index64 + (index64 < 0) * (list->length + 1) - 1; \
+ (off >= 0 && off < list->length) ? ({ \
+ item_type nonnone_var = *(item_type *)(list->data + off * list->stride); \
+ List$remove_at(list, index, I_small(1), sizeof(item_type)); \
+ nonnone_expr; \
+ }) \
+ : none_expr; \
+ })
OptionalInt_t List$find(List_t list, void *item, const TypeInfo_t *type);
-#define List$find_value(list, item_expr, type) ({ __typeof(item_expr) item = item_expr; List$find(list, &item, type); })
+#define List$find_value(list, item_expr, type) \
+ ({ \
+ __typeof(item_expr) item = item_expr; \
+ List$find(list, &item, type); \
+ })
OptionalInt_t List$first(List_t list, Closure_t predicate);
void List$sort(List_t *list, Closure_t comparison, int64_t padded_item_size);
List_t List$sorted(List_t list, Closure_t comparison, int64_t padded_item_size);
void List$shuffle(List_t *list, OptionalClosure_t random_int64, int64_t padded_item_size);
List_t List$shuffled(List_t list, OptionalClosure_t random_int64, int64_t padded_item_size);
void *List$random(List_t list, OptionalClosure_t random_int64);
-#define List$random_value(list, random_int64, t) ({ List_t _arr = list; if (_arr.length == 0) fail("Cannot get a random value from an empty list!"); *(t*)List$random(_arr, random_int64); })
+#define List$random_value(list, random_int64, t) \
+ ({ \
+ List_t _arr = list; \
+ if (_arr.length == 0) fail("Cannot get a random value from an empty list!"); \
+ *(t *)List$random(_arr, random_int64); \
+ })
List_t List$sample(List_t list, Int_t n, List_t weights, Closure_t random_num, int64_t padded_item_size);
Table_t List$counts(List_t list, const TypeInfo_t *type);
void List$clear(List_t *list);
void List$compact(List_t *list, int64_t padded_item_size);
PUREFUNC bool List$has(List_t list, void *item, const TypeInfo_t *type);
-#define List$has_value(list, item_expr, type) ({ __typeof(item_expr) item = item_expr; List$has(list, &item, type); })
+#define List$has_value(list, item_expr, type) \
+ ({ \
+ __typeof(item_expr) item = item_expr; \
+ List$has(list, &item, type); \
+ })
PUREFUNC List_t List$from(List_t list, Int_t first);
PUREFUNC List_t List$to(List_t list, Int_t last);
PUREFUNC List_t List$by(List_t list, Int_t stride, int64_t padded_item_size);
@@ -101,37 +154,51 @@ List_t List$concat(List_t x, List_t y, int64_t padded_item_size);
PUREFUNC uint64_t List$hash(const void *list, const TypeInfo_t *type);
PUREFUNC int32_t List$compare(const void *x, const void *y, const TypeInfo_t *type);
PUREFUNC bool List$equal(const void *x, const void *y, const TypeInfo_t *type);
-PUREFUNC bool List$is_none(const void *obj, const TypeInfo_t*);
+PUREFUNC bool List$is_none(const void *obj, const TypeInfo_t *);
Text_t List$as_text(const void *list, bool colorize, const TypeInfo_t *type);
void List$heapify(List_t *heap, Closure_t comparison, int64_t padded_item_size);
void List$heap_push(List_t *heap, const void *item, Closure_t comparison, int64_t padded_item_size);
-#define List$heap_push_value(heap, _value, comparison, padded_item_size) ({ __typeof(_value) value = _value; List$heap_push(heap, &value, comparison, padded_item_size); })
+#define List$heap_push_value(heap, _value, comparison, padded_item_size) \
+ ({ \
+ __typeof(_value) value = _value; \
+ List$heap_push(heap, &value, comparison, padded_item_size); \
+ })
void List$heap_pop(List_t *heap, Closure_t comparison, int64_t padded_item_size);
-#define List$heap_pop_value(heap, comparison, type, nonnone_var, nonnone_expr, none_expr) \
- ({ List_t *_heap = heap; \
- (_heap->length > 0) ? ({ \
- type nonnone_var = *(type*)_heap->data; \
- List$heap_pop(_heap, comparison, sizeof(type)); \
- nonnone_expr; \
- }) : none_expr; })
+#define List$heap_pop_value(heap, comparison, type, nonnone_var, nonnone_expr, none_expr) \
+ ({ \
+ List_t *_heap = heap; \
+ (_heap->length > 0) ? ({ \
+ type nonnone_var = *(type *)_heap->data; \
+ List$heap_pop(_heap, comparison, sizeof(type)); \
+ nonnone_expr; \
+ }) \
+ : none_expr; \
+ })
Int_t List$binary_search(List_t list, void *target, Closure_t comparison);
-#define List$binary_search_value(list, target, comparison) \
- ({ __typeof(target) _target = target; List$binary_search(list, &_target, comparison); })
+#define List$binary_search_value(list, target, comparison) \
+ ({ \
+ __typeof(target) _target = target; \
+ List$binary_search(list, &_target, comparison); \
+ })
void List$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type);
void List$deserialize(FILE *in, void *obj, List_t *pointers, const TypeInfo_t *type);
-#define List$metamethods { \
- .as_text=List$as_text, \
- .compare=List$compare, \
- .equal=List$equal, \
- .hash=List$hash, \
- .is_none=List$is_none, \
- .serialize=List$serialize, \
- .deserialize=List$deserialize, \
-}
+#define List$metamethods \
+ { \
+ .as_text = List$as_text, \
+ .compare = List$compare, \
+ .equal = List$equal, \
+ .hash = List$hash, \
+ .is_none = List$is_none, \
+ .serialize = List$serialize, \
+ .deserialize = List$deserialize, \
+ }
-#define List$info(item_info) &((TypeInfo_t){.size=sizeof(List_t), .align=__alignof__(List_t), \
- .tag=ListInfo, .ListInfo.item=item_info, \
- .metamethods=List$metamethods})
+#define List$info(item_info) \
+ &((TypeInfo_t){.size = sizeof(List_t), \
+ .align = __alignof__(List_t), \
+ .tag = ListInfo, \
+ .ListInfo.item = item_info, \
+ .metamethods = List$metamethods})
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/stdlib/mapmacro.h b/src/stdlib/mapmacro.h
index 5ed7a4b7..68834f8f 100644
--- a/src/stdlib/mapmacro.h
+++ b/src/stdlib/mapmacro.h
@@ -9,7 +9,7 @@
#define EVAL2(...) EVAL1(EVAL1(EVAL1(__VA_ARGS__)))
#define EVAL3(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__)))
#define EVAL4(...) EVAL3(EVAL3(EVAL3(__VA_ARGS__)))
-#define EVAL(...) EVAL4(EVAL4(EVAL4(__VA_ARGS__)))
+#define EVAL(...) EVAL4(EVAL4(EVAL4(__VA_ARGS__)))
#define MAP_END(...)
#define MAP_OUT
@@ -21,7 +21,7 @@
#define MAP_NEXT0(test, next, ...) next MAP_OUT
#define MAP_LIST_NEXT1(test, next) MAP_NEXT0(test, MAP_COMMA next, 0)
-#define MAP_LIST_NEXT(test, next) MAP_LIST_NEXT1(MAP_GET_END test, next)
+#define MAP_LIST_NEXT(test, next) MAP_LIST_NEXT1(MAP_GET_END test, next)
#define MAP_LIST0(f, x, peek, ...) f(x) MAP_LIST_NEXT(peek, MAP_LIST1)(f, peek, __VA_ARGS__)
#define MAP_LIST1(f, x, peek, ...) f(x) MAP_LIST_NEXT(peek, MAP_LIST0)(f, peek, __VA_ARGS__)
diff --git a/src/stdlib/memory.c b/src/stdlib/memory.c
index a28b0069..90e14261 100644
--- a/src/stdlib/memory.c
+++ b/src/stdlib/memory.c
@@ -1,9 +1,9 @@
// Type info and methods for "Memory" opaque type
+#include <err.h>
#include <gc.h>
#include <stdbool.h>
#include <stdint.h>
#include <sys/param.h>
-#include <err.h>
#include "memory.h"
#include "metamethods.h"
@@ -12,21 +12,24 @@
#include "types.h"
#include "util.h"
-public Text_t Memory$as_text(const void *p, bool colorize, const TypeInfo_t *info) {
+public
+Text_t Memory$as_text(const void *p, bool colorize, const TypeInfo_t *info) {
(void)info;
if (!p) return Text("Memory");
- Text_t text = Text$from_str(String("Memory<", *(void**)p, ">"));
+ Text_t text = Text$from_str(String("Memory<", *(void **)p, ">"));
return colorize ? Texts(Text("\x1b[0;34;1m"), text, Text("\x1b[m")) : text;
}
-public const TypeInfo_t Memory$info = {
- .size=0,
- .align=0,
- .metamethods={
- .as_text=Memory$as_text,
- .serialize=cannot_serialize,
- .deserialize=cannot_deserialize,
- },
+public
+const TypeInfo_t Memory$info = {
+ .size = 0,
+ .align = 0,
+ .metamethods =
+ {
+ .as_text = Memory$as_text,
+ .serialize = cannot_serialize,
+ .deserialize = cannot_deserialize,
+ },
};
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/stdlib/metamethods.c b/src/stdlib/metamethods.c
index 8c755c59..ea06d20b 100644
--- a/src/stdlib/metamethods.c
+++ b/src/stdlib/metamethods.c
@@ -9,52 +9,44 @@
#include "types.h"
#include "util.h"
-PUREFUNC public uint64_t generic_hash(const void *obj, const TypeInfo_t *type)
-{
- if (type->metamethods.hash)
- return type->metamethods.hash(obj, type);
+PUREFUNC public uint64_t generic_hash(const void *obj, const TypeInfo_t *type) {
+ if (type->metamethods.hash) return type->metamethods.hash(obj, type);
- return siphash24((void*)obj, (size_t)(type->size));
+ return siphash24((void *)obj, (size_t)(type->size));
}
-PUREFUNC public int32_t generic_compare(const void *x, const void *y, const TypeInfo_t *type)
-{
+PUREFUNC public int32_t generic_compare(const void *x, const void *y, const TypeInfo_t *type) {
if (x == y) return 0;
- if (type->metamethods.compare)
- return type->metamethods.compare(x, y, type);
+ if (type->metamethods.compare) return type->metamethods.compare(x, y, type);
- return (int32_t)memcmp((void*)x, (void*)y, (size_t)(type->size));
+ return (int32_t)memcmp((void *)x, (void *)y, (size_t)(type->size));
}
-PUREFUNC public bool generic_equal(const void *x, const void *y, const TypeInfo_t *type)
-{
+PUREFUNC public bool generic_equal(const void *x, const void *y, const TypeInfo_t *type) {
if (x == y) return true;
- if (type->metamethods.equal)
- return type->metamethods.equal(x, y, type);
+ if (type->metamethods.equal) return type->metamethods.equal(x, y, type);
return (generic_compare(x, y, type) == 0);
}
-public Text_t generic_as_text(const void *obj, bool colorize, const TypeInfo_t *type)
-{
- if (!type->metamethods.as_text)
- fail("No text metamethod provided for type!");
+public
+Text_t generic_as_text(const void *obj, bool colorize, const TypeInfo_t *type) {
+ if (!type->metamethods.as_text) fail("No text metamethod provided for type!");
return type->metamethods.as_text(obj, colorize, type);
}
-public void _serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type)
-{
- if (type->metamethods.serialize)
- return type->metamethods.serialize(obj, out, pointers, type);
+public
+void _serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type) {
+ if (type->metamethods.serialize) return type->metamethods.serialize(obj, out, pointers, type);
fwrite(obj, (size_t)type->size, 1, out);
}
-public List_t generic_serialize(const void *x, const TypeInfo_t *type)
-{
+public
+List_t generic_serialize(const void *x, const TypeInfo_t *type) {
char *buf = NULL;
size_t size = 0;
FILE *stream = open_memstream(&buf, &size);
@@ -62,31 +54,29 @@ public List_t generic_serialize(const void *x, const TypeInfo_t *type)
_serialize(x, stream, &pointers, type);
fclose(stream);
List_t bytes = {
- .data=GC_MALLOC_ATOMIC(size),
- .length=(int64_t)size,
- .stride=1,
- .atomic=1,
+ .data = GC_MALLOC_ATOMIC(size),
+ .length = (int64_t)size,
+ .stride = 1,
+ .atomic = 1,
};
memcpy(bytes.data, buf, size);
free(buf);
return bytes;
}
-public void _deserialize(FILE *input, void *outval, List_t *pointers, const TypeInfo_t *type)
-{
+public
+void _deserialize(FILE *input, void *outval, List_t *pointers, const TypeInfo_t *type) {
if (type->metamethods.deserialize) {
type->metamethods.deserialize(input, outval, pointers, type);
return;
}
- if (fread(outval, (size_t)type->size, 1, input) != 1)
- fail("Not enough data in stream to deserialize");
+ if (fread(outval, (size_t)type->size, 1, input) != 1) fail("Not enough data in stream to deserialize");
}
-public void generic_deserialize(List_t bytes, void *outval, const TypeInfo_t *type)
-{
- if (bytes.stride != 1)
- List$compact(&bytes, 1);
+public
+void generic_deserialize(List_t bytes, void *outval, const TypeInfo_t *type) {
+ if (bytes.stride != 1) List$compact(&bytes, 1);
FILE *input = fmemopen(bytes.data, (size_t)bytes.length, "r");
List_t pointers = {};
@@ -94,23 +84,21 @@ public void generic_deserialize(List_t bytes, void *outval, const TypeInfo_t *ty
fclose(input);
}
-public int generic_print(const void *obj, bool colorize, const TypeInfo_t *type)
-{
+public
+int generic_print(const void *obj, bool colorize, const TypeInfo_t *type) {
Text_t text = generic_as_text(obj, colorize, type);
return Text$print(stdout, text) + fputc('\n', stdout);
}
-__attribute__((noreturn))
-public void cannot_serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type)
-{
+__attribute__((noreturn)) public
+void cannot_serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type) {
(void)obj, (void)out, (void)pointers;
Text_t typestr = generic_as_text(NULL, false, type);
fail("Values of type ", typestr, " cannot be serialized or deserialized!");
}
-__attribute__((noreturn))
-public void cannot_deserialize(FILE *in, void *obj, List_t *pointers, const TypeInfo_t *type)
-{
+__attribute__((noreturn)) public
+void cannot_deserialize(FILE *in, void *obj, List_t *pointers, const TypeInfo_t *type) {
(void)obj, (void)in, (void)pointers;
Text_t typestr = generic_as_text(NULL, false, type);
fail("Values of type ", typestr, " cannot be serialized or deserialized!");
diff --git a/src/stdlib/metamethods.h b/src/stdlib/metamethods.h
index ca0a1e7e..eda2230e 100644
--- a/src/stdlib/metamethods.h
+++ b/src/stdlib/metamethods.h
@@ -16,7 +16,7 @@ List_t generic_serialize(const void *x, const TypeInfo_t *type);
void _deserialize(FILE *input, void *outval, List_t *pointers, const TypeInfo_t *type);
void generic_deserialize(List_t bytes, void *outval, const TypeInfo_t *type);
int generic_print(const void *obj, bool colorize, const TypeInfo_t *type);
-void cannot_serialize(const void*, FILE*, Table_t*, const TypeInfo_t *type);
-void cannot_deserialize(FILE*, void*, List_t*, const TypeInfo_t *type);
+void cannot_serialize(const void *, FILE *, Table_t *, const TypeInfo_t *type);
+void cannot_deserialize(FILE *, void *, List_t *, const TypeInfo_t *type);
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/stdlib/nums.c b/src/stdlib/nums.c
index 83166659..05ed14a8 100644
--- a/src/stdlib/nums.c
+++ b/src/stdlib/nums.c
@@ -13,20 +13,21 @@
#include "text.h"
#include "types.h"
-public PUREFUNC Text_t Num$as_text(const void *f, bool colorize, const TypeInfo_t *info) {
+public
+PUREFUNC Text_t Num$as_text(const void *f, bool colorize, const TypeInfo_t *info) {
(void)info;
if (!f) return Text("Num");
char *str = GC_MALLOC_ATOMIC(24);
- int len = fpconv_dtoa(*(double*)f, str);
+ int len = fpconv_dtoa(*(double *)f, str);
static const Text_t color_prefix = Text("\x1b[35m"), color_suffix = Text("\x1b[m");
Text_t text = Text$from_strn(str, (size_t)len);
return colorize ? Texts(color_prefix, text, color_suffix) : text;
-}
+}
-public PUREFUNC int32_t Num$compare(const void *x, const void *y, const TypeInfo_t *info) {
+public
+PUREFUNC int32_t Num$compare(const void *x, const void *y, const TypeInfo_t *info) {
(void)info;
- int64_t rx = *(int64_t*)x,
- ry = *(int64_t*)y;
+ int64_t rx = *(int64_t *)x, ry = *(int64_t *)y;
if (rx == ry) return 0;
@@ -34,14 +35,16 @@ public PUREFUNC int32_t Num$compare(const void *x, const void *y, const TypeInfo
if (ry < 0) ry ^= INT64_MAX;
return (rx > ry) - (rx < ry);
-}
+}
-public PUREFUNC bool Num$equal(const void *x, const void *y, const TypeInfo_t *info) {
+public
+PUREFUNC bool Num$equal(const void *x, const void *y, const TypeInfo_t *info) {
(void)info;
- return *(double*)x == *(double*)y;
-}
+ return *(double *)x == *(double *)y;
+}
-public CONSTFUNC bool Num$near(double a, double b, double ratio, double absolute) {
+public
+CONSTFUNC bool Num$near(double a, double b, double ratio, double absolute) {
if (ratio < 0) ratio = 0;
else if (ratio > 1) ratio = 1;
@@ -56,17 +59,19 @@ public CONSTFUNC bool Num$near(double a, double b, double ratio, double absolute
return (diff < epsilon);
}
-public Text_t Num$percent(double f, double precision) {
+public
+Text_t Num$percent(double f, double precision) {
double d = 100. * f;
d = Num$with_precision(d, precision);
return Texts(Num$as_text(&d, false, &Num$info), Text("%"));
}
-public CONSTFUNC double Num$with_precision(double num, double precision) {
+public
+CONSTFUNC double Num$with_precision(double num, double precision) {
if (precision == 0.0) return num;
// Precision will be, e.g. 0.01 or 100.
if (precision < 1.) {
- double inv = round(1./precision); // Necessary to make the math work
+ double inv = round(1. / precision); // Necessary to make the math work
double k = num * inv;
return round(k) / inv;
} else {
@@ -75,37 +80,34 @@ public CONSTFUNC double Num$with_precision(double num, double precision) {
}
}
-public CONSTFUNC double Num$mod(double num, double modulus) {
- // Euclidean division, see: https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf
+public
+CONSTFUNC double Num$mod(double num, double modulus) {
+ // Euclidean division, see:
+ // https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf
double r = remainder(num, modulus);
- r -= (r < 0) * (2*(modulus < 0) - 1) * modulus;
+ r -= (r < 0) * (2 * (modulus < 0) - 1) * modulus;
return r;
}
-public CONSTFUNC double Num$mod1(double num, double modulus) {
- return 1.0 + Num$mod(num-1, modulus);
-}
+public
+CONSTFUNC double Num$mod1(double num, double modulus) { return 1.0 + Num$mod(num - 1, modulus); }
-public CONSTFUNC double Num$mix(double amount, double x, double y) {
- return (1.0-amount)*x + amount*y;
-}
+public
+CONSTFUNC double Num$mix(double amount, double x, double y) { return (1.0 - amount) * x + amount * y; }
-public CONSTFUNC bool Num$is_between(const double x, const double low, const double high) {
- return low <= x && x <= high;
-}
-public CONSTFUNC double Num$clamped(double x, double low, double high) {
- return (x <= low) ? low : (x >= high ? high : x);
-}
+public
+CONSTFUNC bool Num$is_between(const double x, const double low, const double high) { return low <= x && x <= high; }
+public
+CONSTFUNC double Num$clamped(double x, double low, double high) { return (x <= low) ? low : (x >= high ? high : x); }
-public OptionalNum_t Num$parse(Text_t text, Text_t *remainder) {
+public
+OptionalNum_t Num$parse(Text_t text, Text_t *remainder) {
const char *str = Text$as_c_string(text);
char *end = NULL;
double d = strtod(str, &end);
if (end > str) {
- if (remainder)
- *remainder = Text$from_str(end);
- else if (*end != '\0')
- return nan("none");
+ if (remainder) *remainder = Text$from_str(end);
+ else if (*end != '\0') return nan("none");
return d;
} else {
if (remainder) *remainder = text;
@@ -113,45 +115,54 @@ public OptionalNum_t Num$parse(Text_t text, Text_t *remainder) {
}
}
-public CONSTFUNC bool Num$is_none(const void *n, const TypeInfo_t *info)
-{
+public
+CONSTFUNC bool Num$is_none(const void *n, const TypeInfo_t *info) {
(void)info;
- return isnan(*(Num_t*)n);
-}
-
-public CONSTFUNC bool Num$isinf(double n) { return (fpclassify(n) == FP_INFINITE); }
-public CONSTFUNC bool Num$finite(double n) { return (fpclassify(n) != FP_INFINITE); }
-public CONSTFUNC bool Num$isnan(double n) { return (fpclassify(n) == FP_NAN); }
-
-public const TypeInfo_t Num$info = {
- .size=sizeof(double),
- .align=__alignof__(double),
- .metamethods={
- .compare=Num$compare,
- .equal=Num$equal,
- .as_text=Num$as_text,
- .is_none=Num$is_none,
- },
+ return isnan(*(Num_t *)n);
+}
+
+public
+CONSTFUNC bool Num$isinf(double n) { return (fpclassify(n) == FP_INFINITE); }
+public
+CONSTFUNC bool Num$finite(double n) { return (fpclassify(n) != FP_INFINITE); }
+public
+CONSTFUNC bool Num$isnan(double n) { return (fpclassify(n) == FP_NAN); }
+
+public
+const TypeInfo_t Num$info = {
+ .size = sizeof(double),
+ .align = __alignof__(double),
+ .metamethods =
+ {
+ .compare = Num$compare,
+ .equal = Num$equal,
+ .as_text = Num$as_text,
+ .is_none = Num$is_none,
+ },
};
-public PUREFUNC Text_t Num32$as_text(const void *f, bool colorize, const TypeInfo_t *info) {
+public
+PUREFUNC Text_t Num32$as_text(const void *f, bool colorize, const TypeInfo_t *info) {
(void)info;
if (!f) return Text("Num32");
- double d = (double)(*(float*)f);
+ double d = (double)(*(float *)f);
return Num$as_text(&d, colorize, &Num$info);
}
-public PUREFUNC int32_t Num32$compare(const void *x, const void *y, const TypeInfo_t *info) {
+public
+PUREFUNC int32_t Num32$compare(const void *x, const void *y, const TypeInfo_t *info) {
(void)info;
- return (*(float*)x > *(float*)y) - (*(float*)x < *(float*)y);
-}
+ return (*(float *)x > *(float *)y) - (*(float *)x < *(float *)y);
+}
-public PUREFUNC bool Num32$equal(const void *x, const void *y, const TypeInfo_t *info) {
+public
+PUREFUNC bool Num32$equal(const void *x, const void *y, const TypeInfo_t *info) {
(void)info;
- return *(float*)x == *(float*)y;
+ return *(float *)x == *(float *)y;
}
-public CONSTFUNC bool Num32$near(float a, float b, float ratio, float absolute) {
+public
+CONSTFUNC bool Num32$near(float a, float b, float ratio, float absolute) {
if (ratio < 0) ratio = 0;
else if (ratio > 1) ratio = 1;
@@ -166,17 +177,19 @@ public CONSTFUNC bool Num32$near(float a, float b, float ratio, float absolute)
return (diff < epsilon);
}
-public Text_t Num32$percent(float f, float precision) {
+public
+Text_t Num32$percent(float f, float precision) {
double d = 100. * (double)f;
d = Num$with_precision(d, (double)precision);
return Texts(Num$as_text(&d, false, &Num$info), Text("%"));
}
-public CONSTFUNC float Num32$with_precision(float num, float precision) {
+public
+CONSTFUNC float Num32$with_precision(float num, float precision) {
if (precision == 0.0f) return num;
// Precision will be, e.g. 0.01 or 100.
if (precision < 1.f) {
- float inv = roundf(1.f/precision); // Necessary to make the math work
+ float inv = roundf(1.f / precision); // Necessary to make the math work
float k = num * inv;
return roundf(k) / inv;
} else {
@@ -185,37 +198,35 @@ public CONSTFUNC float Num32$with_precision(float num, float precision) {
}
}
-public CONSTFUNC float Num32$mod(float num, float modulus) {
- // Euclidean division, see: https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf
+public
+CONSTFUNC float Num32$mod(float num, float modulus) {
+ // Euclidean division, see:
+ // https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf
float r = remainderf(num, modulus);
- r -= (r < 0) * (2*(modulus < 0) - 1) * modulus;
+ r -= (r < 0) * (2 * (modulus < 0) - 1) * modulus;
return r;
}
-public CONSTFUNC float Num32$mod1(float num, float modulus) {
- return 1.0f + Num32$mod(num-1, modulus);
-}
+public
+CONSTFUNC float Num32$mod1(float num, float modulus) { return 1.0f + Num32$mod(num - 1, modulus); }
-public CONSTFUNC float Num32$mix(float amount, float x, float y) {
- return (1.0f-amount)*x + amount*y;
-}
+public
+CONSTFUNC float Num32$mix(float amount, float x, float y) { return (1.0f - amount) * x + amount * y; }
-public CONSTFUNC bool Num32$is_between(const float x, const float low, const float high) {
- return low <= x && x <= high;
-}
+public
+CONSTFUNC bool Num32$is_between(const float x, const float low, const float high) { return low <= x && x <= high; }
-public CONSTFUNC float Num32$clamped(float x, float low, float high) {
- return (x <= low) ? low : (x >= high ? high : x);
-}
+public
+CONSTFUNC float Num32$clamped(float x, float low, float high) { return (x <= low) ? low : (x >= high ? high : x); }
-public OptionalNum32_t Num32$parse(Text_t text, Text_t *remainder) {
+public
+OptionalNum32_t Num32$parse(Text_t text, Text_t *remainder) {
const char *str = Text$as_c_string(text);
char *end = NULL;
double d = strtod(str, &end);
if (end > str && end[0] == '\0') {
if (remainder) *remainder = Text$from_str(end);
- else if (*end != '\0')
- return nan("none");
+ else if (*end != '\0') return nan("none");
return d;
} else {
if (remainder) *remainder = text;
@@ -223,25 +234,30 @@ public OptionalNum32_t Num32$parse(Text_t text, Text_t *remainder) {
}
}
-public CONSTFUNC bool Num32$is_none(const void *n, const TypeInfo_t *info)
-{
+public
+CONSTFUNC bool Num32$is_none(const void *n, const TypeInfo_t *info) {
(void)info;
- return isnan(*(Num32_t*)n);
-}
-
-public CONSTFUNC bool Num32$isinf(float n) { return (fpclassify(n) == FP_INFINITE); }
-public CONSTFUNC bool Num32$finite(float n) { return (fpclassify(n) != FP_INFINITE); }
-public CONSTFUNC bool Num32$isnan(float n) { return (fpclassify(n) == FP_NAN); }
-
-public const TypeInfo_t Num32$info = {
- .size=sizeof(float),
- .align=__alignof__(float),
- .metamethods={
- .compare=Num32$compare,
- .equal=Num32$equal,
- .as_text=Num32$as_text,
- .is_none=Num32$is_none,
- },
+ return isnan(*(Num32_t *)n);
+}
+
+public
+CONSTFUNC bool Num32$isinf(float n) { return (fpclassify(n) == FP_INFINITE); }
+public
+CONSTFUNC bool Num32$finite(float n) { return (fpclassify(n) != FP_INFINITE); }
+public
+CONSTFUNC bool Num32$isnan(float n) { return (fpclassify(n) == FP_NAN); }
+
+public
+const TypeInfo_t Num32$info = {
+ .size = sizeof(float),
+ .align = __alignof__(float),
+ .metamethods =
+ {
+ .compare = Num32$compare,
+ .equal = Num32$equal,
+ .as_text = Num32$as_text,
+ .is_none = Num32$is_none,
+ },
};
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/stdlib/optionals.c b/src/stdlib/optionals.c
index 36683241..a6f943ae 100644
--- a/src/stdlib/optionals.c
+++ b/src/stdlib/optionals.c
@@ -9,22 +9,19 @@
#include "text.h"
#include "util.h"
-public PUREFUNC bool is_none(const void *obj, const TypeInfo_t *non_optional_type)
-{
- if (non_optional_type->metamethods.is_none)
- return non_optional_type->metamethods.is_none(obj, non_optional_type);
+public
+PUREFUNC bool is_none(const void *obj, const TypeInfo_t *non_optional_type) {
+ if (non_optional_type->metamethods.is_none) return non_optional_type->metamethods.is_none(obj, non_optional_type);
const void *dest = (obj + non_optional_type->size);
- return *(bool*)dest;
+ return *(bool *)dest;
}
-PUREFUNC public uint64_t Optional$hash(const void *obj, const TypeInfo_t *type)
-{
+PUREFUNC public uint64_t Optional$hash(const void *obj, const TypeInfo_t *type) {
return is_none(obj, type->OptionalInfo.type) ? 0 : generic_hash(obj, type->OptionalInfo.type);
}
-PUREFUNC public int32_t Optional$compare(const void *x, const void *y, const TypeInfo_t *type)
-{
+PUREFUNC public int32_t Optional$compare(const void *x, const void *y, const TypeInfo_t *type) {
if (x == y) return 0;
bool x_is_null = is_none(x, type->OptionalInfo.type);
bool y_is_null = is_none(y, type->OptionalInfo.type);
@@ -33,8 +30,7 @@ PUREFUNC public int32_t Optional$compare(const void *x, const void *y, const Typ
else return generic_compare(x, y, type->OptionalInfo.type);
}
-PUREFUNC public bool Optional$equal(const void *x, const void *y, const TypeInfo_t *type)
-{
+PUREFUNC public bool Optional$equal(const void *x, const void *y, const TypeInfo_t *type) {
if (x == y) return true;
bool x_is_null = is_none(x, type->OptionalInfo.type);
@@ -44,46 +40,37 @@ PUREFUNC public bool Optional$equal(const void *x, const void *y, const TypeInfo
else return generic_equal(x, y, type->OptionalInfo.type);
}
-public Text_t Optional$as_text(const void *obj, bool colorize, const TypeInfo_t *type)
-{
- if (!obj)
- return Text$concat(generic_as_text(obj, colorize, type->OptionalInfo.type), Text("?"));
+public
+Text_t Optional$as_text(const void *obj, bool colorize, const TypeInfo_t *type) {
+ if (!obj) return Text$concat(generic_as_text(obj, colorize, type->OptionalInfo.type), Text("?"));
- if (is_none(obj, type->OptionalInfo.type))
- return colorize ? Text("\x1b[31mnone\x1b[m") : Text("none");
+ if (is_none(obj, type->OptionalInfo.type)) return colorize ? Text("\x1b[31mnone\x1b[m") : Text("none");
return generic_as_text(obj, colorize, type->OptionalInfo.type);
}
-public void Optional$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type)
-{
+public
+void Optional$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type) {
bool has_value = !is_none(obj, type->OptionalInfo.type);
assert(fputc((int)has_value, out) != EOF);
- if (has_value)
- _serialize(obj, out, pointers, type->OptionalInfo.type);
+ if (has_value) _serialize(obj, out, pointers, type->OptionalInfo.type);
}
-public void Optional$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *type)
-{
+public
+void Optional$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *type) {
bool has_value = (bool)fgetc(in);
const TypeInfo_t *nonnull = type->OptionalInfo.type;
if (has_value) {
memset(outval, 0, (size_t)type->size);
_deserialize(in, outval, pointers, nonnull);
} else {
- if (nonnull->tag == TextInfo)
- *(Text_t*)outval = NONE_TEXT;
- else if (nonnull->tag == ListInfo)
- *(List_t*)outval = (List_t){.length=-1};
- else if (nonnull->tag == TableInfo)
- *(Table_t*)outval = (Table_t){.entries={.length=-1}};
- else if (nonnull == &Num$info)
- *(double*)outval = (double)NAN;
- else if (nonnull == &Num32$info)
- *(float*)outval = (float)NAN;
+ if (nonnull->tag == TextInfo) *(Text_t *)outval = NONE_TEXT;
+ else if (nonnull->tag == ListInfo) *(List_t *)outval = (List_t){.length = -1};
+ else if (nonnull->tag == TableInfo) *(Table_t *)outval = (Table_t){.entries = {.length = -1}};
+ else if (nonnull == &Num$info) *(double *)outval = (double)NAN;
+ else if (nonnull == &Num32$info) *(float *)outval = (float)NAN;
else if (nonnull->tag == StructInfo || (nonnull->tag == OpaqueInfo && type->size > nonnull->size))
memset(outval + type->size, -1, (size_t)(type->size - nonnull->size));
- else
- memset(outval, 0, (size_t)type->size);
+ else memset(outval, 0, (size_t)type->size);
}
}
diff --git a/src/stdlib/optionals.h b/src/stdlib/optionals.h
index bd1f63b3..77ce6db4 100644
--- a/src/stdlib/optionals.h
+++ b/src/stdlib/optionals.h
@@ -9,13 +9,13 @@
#include "types.h"
#include "util.h"
-#define NONE_LIST ((List_t){.length=-1})
+#define NONE_LIST ((List_t){.length = -1})
#define NONE_BOOL ((OptionalBool_t)2)
-#define NONE_INT ((OptionalInt_t){.small=0})
-#define NONE_TABLE ((OptionalTable_t){.entries.length=-1})
-#define NONE_CLOSURE ((OptionalClosure_t){.fn=NULL})
-#define NONE_TEXT ((OptionalText_t){.length=-1})
-#define NONE_PATH ((Path_t){.type=PATH_NONE})
+#define NONE_INT ((OptionalInt_t){.small = 0})
+#define NONE_TABLE ((OptionalTable_t){.entries.length = -1})
+#define NONE_CLOSURE ((OptionalClosure_t){.fn = NULL})
+#define NONE_TEXT ((OptionalText_t){.length = -1})
+#define NONE_PATH ((Path_t){.type = PATH_NONE})
PUREFUNC bool is_none(const void *obj, const TypeInfo_t *non_optional_type);
PUREFUNC uint64_t Optional$hash(const void *obj, const TypeInfo_t *type);
@@ -25,17 +25,21 @@ Text_t Optional$as_text(const void *obj, bool colorize, const TypeInfo_t *type);
void Optional$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type);
void Optional$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *type);
-#define Optional$metamethods { \
- .hash=Optional$hash, \
- .compare=Optional$compare, \
- .equal=Optional$equal, \
- .as_text=Optional$as_text, \
- .serialize=Optional$serialize, \
- .deserialize=Optional$deserialize, \
-}
-
-#define Optional$info(_size, _align, t) &((TypeInfo_t){.size=_size, .align=_align, \
- .tag=OptionalInfo, .OptionalInfo.type=t, \
- .metamethods=Optional$metamethods})
+#define Optional$metamethods \
+ { \
+ .hash = Optional$hash, \
+ .compare = Optional$compare, \
+ .equal = Optional$equal, \
+ .as_text = Optional$as_text, \
+ .serialize = Optional$serialize, \
+ .deserialize = Optional$deserialize, \
+ }
+
+#define Optional$info(_size, _align, t) \
+ &((TypeInfo_t){.size = _size, \
+ .align = _align, \
+ .tag = OptionalInfo, \
+ .OptionalInfo.type = t, \
+ .metamethods = Optional$metamethods})
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/stdlib/paths.c b/src/stdlib/paths.c
index a14b32c2..efe9f7ad 100644
--- a/src/stdlib/paths.c
+++ b/src/stdlib/paths.c
@@ -17,32 +17,30 @@
#include <unistd.h>
#include <unistr.h>
-#include "lists.h"
#include "enums.h"
#include "integers.h"
+#include "lists.h"
#include "optionals.h"
#include "paths.h"
+#include "print.h"
#include "structs.h"
#include "text.h"
#include "types.h"
#include "util.h"
-#include "print.h"
// Use inline version of the siphash code for performance:
#include "siphash-internals.h"
-static const Path_t HOME_PATH = {.type.$tag=PATH_HOME},
- ROOT_PATH = {.type.$tag=PATH_ABSOLUTE},
- CURDIR_PATH = {.type.$tag=PATH_RELATIVE};
+static const Path_t HOME_PATH = {.type.$tag = PATH_HOME}, ROOT_PATH = {.type.$tag = PATH_ABSOLUTE},
+ CURDIR_PATH = {.type.$tag = PATH_RELATIVE};
-static void clean_components(List_t *components)
-{
- for (int64_t i = 0; i < components->length; ) {
- Text_t *component = (Text_t*)(components->data + i*components->stride);
+static void clean_components(List_t *components) {
+ for (int64_t i = 0; i < components->length;) {
+ Text_t *component = (Text_t *)(components->data + i * components->stride);
if (component->length == 0 || Text$equal_values(*component, Text("."))) {
- List$remove_at(components, I(i+1), I(1), sizeof(Text_t));
+ List$remove_at(components, I(i + 1), I(1), sizeof(Text_t));
} else if (i > 0 && Text$equal_values(*component, Text(".."))) {
- Text_t *prev = (Text_t*)(components->data + (i-1)*components->stride);
+ Text_t *prev = (Text_t *)(components->data + (i - 1) * components->stride);
if (!Text$equal_values(*prev, Text(".."))) {
List$remove_at(components, I(i), I(2), sizeof(Text_t));
i -= 1;
@@ -55,16 +53,15 @@ static void clean_components(List_t *components)
}
}
-public Path_t Path$from_str(const char *str)
-{
+public
+Path_t Path$from_str(const char *str) {
if (!str || str[0] == '\0' || streq(str, "/")) return ROOT_PATH;
else if (streq(str, "~")) return HOME_PATH;
else if (streq(str, ".")) return CURDIR_PATH;
- if (strchr(str, ';') != NULL)
- fail("Path has illegal character (semicolon): ", str);
+ if (strchr(str, ';') != NULL) fail("Path has illegal character (semicolon): ", str);
- Path_t result = {.components={}};
+ Path_t result = {.components = {}};
if (str[0] == '/') {
result.type.$tag = PATH_ABSOLUTE;
str += 1;
@@ -83,12 +80,13 @@ public Path_t Path$from_str(const char *str)
if (component_len > 0) {
if (component_len == 1 && str[0] == '.') {
// ignore /./
- } else if (component_len == 2 && strncmp(str, "..", 2) == 0
- && result.components.length > 1
- && !Text$equal_values(Text(".."), *(Text_t*)(result.components.data + result.components.stride*(result.components.length-1)))) {
+ } else if (component_len == 2 && strncmp(str, "..", 2) == 0 && result.components.length > 1
+ && !Text$equal_values(
+ Text(".."), *(Text_t *)(result.components.data
+ + result.components.stride * (result.components.length - 1)))) {
// Pop off /foo/baz/.. -> /foo
List$remove_at(&result.components, I(result.components.length), I(1), sizeof(Text_t));
- } else {
+ } else {
Text_t component = Text$from_strn(str, component_len);
List$insert_value(&result.components, component, I(0), sizeof(Text_t));
}
@@ -99,25 +97,23 @@ public Path_t Path$from_str(const char *str)
return result;
}
-public Path_t Path$from_text(Text_t text)
-{
- return Path$from_str(Text$as_c_string(text));
-}
+public
+Path_t Path$from_text(Text_t text) { return Path$from_str(Text$as_c_string(text)); }
-public Path_t Path$expand_home(Path_t path)
-{
+public
+Path_t Path$expand_home(Path_t path) {
if (path.type.$tag == PATH_HOME) {
Path_t pwd = Path$from_str(getenv("HOME"));
List_t components = List$concat(pwd.components, path.components, sizeof(Text_t));
assert(components.length == path.components.length + pwd.components.length);
clean_components(&components);
- path = (Path_t){.type.$tag=PATH_ABSOLUTE, .components=components};
+ path = (Path_t){.type.$tag = PATH_ABSOLUTE, .components = components};
}
return path;
}
-public Path_t Path$_concat(int n, Path_t items[n])
-{
+public
+Path_t Path$_concat(int n, Path_t items[n]) {
assert(n > 0);
Path_t result = items[0];
LIST_INCREF(result.components);
@@ -130,10 +126,11 @@ public Path_t Path$_concat(int n, Path_t items[n])
return result;
}
-public Path_t Path$resolved(Path_t path, Path_t relative_to)
-{
- if (path.type.$tag == PATH_RELATIVE && !(relative_to.type.$tag == PATH_RELATIVE && relative_to.components.length == 0)) {
- Path_t result = {.type.$tag=relative_to.type.$tag};
+public
+Path_t Path$resolved(Path_t path, Path_t relative_to) {
+ if (path.type.$tag == PATH_RELATIVE
+ && !(relative_to.type.$tag == PATH_RELATIVE && relative_to.components.length == 0)) {
+ Path_t result = {.type.$tag = relative_to.type.$tag};
result.components = relative_to.components;
LIST_INCREF(result.components);
List$insert_all(&result.components, path.components, I(0), sizeof(Text_t));
@@ -143,87 +140,86 @@ public Path_t Path$resolved(Path_t path, Path_t relative_to)
return path;
}
-public Path_t Path$relative_to(Path_t path, Path_t relative_to)
-{
+public
+Path_t Path$relative_to(Path_t path, Path_t relative_to) {
if (path.type.$tag != relative_to.type.$tag)
- fail("Cannot create a path relative to a different path with a mismatching type: (", path, ") relative to (", relative_to, ")");
+ fail("Cannot create a path relative to a different path with a mismatching type: (", path, ") relative to (",
+ relative_to, ")");
- Path_t result = {.type.$tag=PATH_RELATIVE};
+ Path_t result = {.type.$tag = PATH_RELATIVE};
int64_t shared = 0;
for (; shared < path.components.length && shared < relative_to.components.length; shared++) {
- Text_t *p = (Text_t*)(path.components.data + shared*path.components.stride);
- Text_t *r = (Text_t*)(relative_to.components.data + shared*relative_to.components.stride);
- if (!Text$equal_values(*p, *r))
- break;
+ Text_t *p = (Text_t *)(path.components.data + shared * path.components.stride);
+ Text_t *r = (Text_t *)(relative_to.components.data + shared * relative_to.components.stride);
+ if (!Text$equal_values(*p, *r)) break;
}
for (int64_t i = shared; i < relative_to.components.length; i++)
List$insert_value(&result.components, Text(".."), I(1), sizeof(Text_t));
for (int64_t i = shared; i < path.components.length; i++) {
- Text_t *p = (Text_t*)(path.components.data + i*path.components.stride);
+ Text_t *p = (Text_t *)(path.components.data + i * path.components.stride);
List$insert(&result.components, p, I(0), sizeof(Text_t));
}
- //clean_components(&result.components);
+ // clean_components(&result.components);
return result;
}
-public bool Path$exists(Path_t path)
-{
+public
+bool Path$exists(Path_t path) {
path = Path$expand_home(path);
struct stat sb;
return (stat(Path$as_c_string(path), &sb) == 0);
}
-static INLINE int path_stat(Path_t path, bool follow_symlinks, struct stat *sb)
-{
+static INLINE int path_stat(Path_t path, bool follow_symlinks, struct stat *sb) {
path = Path$expand_home(path);
const char *path_str = Path$as_c_string(path);
return follow_symlinks ? stat(path_str, sb) : lstat(path_str, sb);
}
-public bool Path$is_file(Path_t path, bool follow_symlinks)
-{
+public
+bool Path$is_file(Path_t path, bool follow_symlinks) {
struct stat sb;
int status = path_stat(path, follow_symlinks, &sb);
if (status != 0) return false;
return (sb.st_mode & S_IFMT) == S_IFREG;
}
-public bool Path$is_directory(Path_t path, bool follow_symlinks)
-{
+public
+bool Path$is_directory(Path_t path, bool follow_symlinks) {
struct stat sb;
int status = path_stat(path, follow_symlinks, &sb);
if (status != 0) return false;
return (sb.st_mode & S_IFMT) == S_IFDIR;
}
-public bool Path$is_pipe(Path_t path, bool follow_symlinks)
-{
+public
+bool Path$is_pipe(Path_t path, bool follow_symlinks) {
struct stat sb;
int status = path_stat(path, follow_symlinks, &sb);
if (status != 0) return false;
return (sb.st_mode & S_IFMT) == S_IFIFO;
}
-public bool Path$is_socket(Path_t path, bool follow_symlinks)
-{
+public
+bool Path$is_socket(Path_t path, bool follow_symlinks) {
struct stat sb;
int status = path_stat(path, follow_symlinks, &sb);
if (status != 0) return false;
return (sb.st_mode & S_IFMT) == S_IFSOCK;
}
-public bool Path$is_symlink(Path_t path)
-{
+public
+bool Path$is_symlink(Path_t path) {
struct stat sb;
int status = path_stat(path, false, &sb);
if (status != 0) return false;
return (sb.st_mode & S_IFMT) == S_IFLNK;
}
-public bool Path$can_read(Path_t path)
-{
+public
+bool Path$can_read(Path_t path) {
path = Path$expand_home(path);
const char *path_str = Path$as_c_string(path);
#ifdef _GNU_SOURCE
@@ -233,8 +229,8 @@ public bool Path$can_read(Path_t path)
#endif
}
-public bool Path$can_write(Path_t path)
-{
+public
+bool Path$can_write(Path_t path) {
path = Path$expand_home(path);
const char *path_str = Path$as_c_string(path);
#ifdef _GNU_SOURCE
@@ -244,8 +240,8 @@ public bool Path$can_write(Path_t path)
#endif
}
-public bool Path$can_execute(Path_t path)
-{
+public
+bool Path$can_execute(Path_t path) {
path = Path$expand_home(path);
const char *path_str = Path$as_c_string(path);
#ifdef _GNU_SOURCE
@@ -255,93 +251,86 @@ public bool Path$can_execute(Path_t path)
#endif
}
-public OptionalInt64_t Path$modified(Path_t path, bool follow_symlinks)
-{
+public
+OptionalInt64_t Path$modified(Path_t path, bool follow_symlinks) {
struct stat sb;
int status = path_stat(path, follow_symlinks, &sb);
if (status != 0) return NONE_INT64;
- return (OptionalInt64_t){.value=(int64_t)sb.st_mtime};
+ return (OptionalInt64_t){.value = (int64_t)sb.st_mtime};
}
-public OptionalInt64_t Path$accessed(Path_t path, bool follow_symlinks)
-{
+public
+OptionalInt64_t Path$accessed(Path_t path, bool follow_symlinks) {
struct stat sb;
int status = path_stat(path, follow_symlinks, &sb);
if (status != 0) return NONE_INT64;
- return (OptionalInt64_t){.value=(int64_t)sb.st_atime};
+ return (OptionalInt64_t){.value = (int64_t)sb.st_atime};
}
-public OptionalInt64_t Path$changed(Path_t path, bool follow_symlinks)
-{
+public
+OptionalInt64_t Path$changed(Path_t path, bool follow_symlinks) {
struct stat sb;
int status = path_stat(path, follow_symlinks, &sb);
if (status != 0) return NONE_INT64;
- return (OptionalInt64_t){.value=(int64_t)sb.st_ctime};
+ return (OptionalInt64_t){.value = (int64_t)sb.st_ctime};
}
-static void _write(Path_t path, List_t bytes, int mode, int permissions)
-{
+static void _write(Path_t path, List_t bytes, int mode, int permissions) {
path = Path$expand_home(path);
const char *path_str = Path$as_c_string(path);
int fd = open(path_str, mode, permissions);
- if (fd == -1)
- fail("Could not write to file: ", path_str, "\n", strerror(errno));
+ if (fd == -1) fail("Could not write to file: ", path_str, "\n", strerror(errno));
- if (bytes.stride != 1)
- List$compact(&bytes, 1);
+ if (bytes.stride != 1) List$compact(&bytes, 1);
ssize_t written = write(fd, bytes.data, (size_t)bytes.length);
- if (written != (ssize_t)bytes.length)
- fail("Could not write to file: ", path_str, "\n", strerror(errno));
+ if (written != (ssize_t)bytes.length) fail("Could not write to file: ", path_str, "\n", strerror(errno));
close(fd);
}
-public void Path$write(Path_t path, Text_t text, int permissions)
-{
+public
+void Path$write(Path_t path, Text_t text, int permissions) {
List_t bytes = Text$utf8_bytes(text);
_write(path, bytes, O_WRONLY | O_CREAT | O_TRUNC, permissions);
}
-public void Path$write_bytes(Path_t path, List_t bytes, int permissions)
-{
+public
+void Path$write_bytes(Path_t path, List_t bytes, int permissions) {
_write(path, bytes, O_WRONLY | O_CREAT | O_TRUNC, permissions);
}
-public void Path$append(Path_t path, Text_t text, int permissions)
-{
+public
+void Path$append(Path_t path, Text_t text, int permissions) {
List_t bytes = Text$utf8_bytes(text);
_write(path, bytes, O_WRONLY | O_APPEND | O_CREAT, permissions);
}
-public void Path$append_bytes(Path_t path, List_t bytes, int permissions)
-{
+public
+void Path$append_bytes(Path_t path, List_t bytes, int permissions) {
_write(path, bytes, O_WRONLY | O_APPEND | O_CREAT, permissions);
}
-public OptionalList_t Path$read_bytes(Path_t path, OptionalInt_t count)
-{
+public
+OptionalList_t Path$read_bytes(Path_t path, OptionalInt_t count) {
path = Path$expand_home(path);
int fd = open(Path$as_c_string(path), O_RDONLY);
- if (fd == -1)
- return NONE_LIST;
+ if (fd == -1) return NONE_LIST;
struct stat sb;
- if (fstat(fd, &sb) != 0)
- return NONE_LIST;
+ if (fstat(fd, &sb) != 0) return NONE_LIST;
int64_t const target_count = count.small ? Int64$from_int(count, false) : INT64_MAX;
- if (target_count < 0)
- fail("Cannot read a negative number of bytes!");
+ if (target_count < 0) fail("Cannot read a negative number of bytes!");
if ((sb.st_mode & S_IFMT) == S_IFREG) { // Use memory mapping if it's a real file:
const char *mem = mmap(NULL, (size_t)sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
- char *content = GC_MALLOC_ATOMIC((size_t)sb.st_size+1);
+ char *content = GC_MALLOC_ATOMIC((size_t)sb.st_size + 1);
memcpy(content, mem, (size_t)sb.st_size);
content[sb.st_size] = '\0';
close(fd);
if (count.small && (int64_t)sb.st_size < target_count)
fail("Could not read ", target_count, " bytes from ", path, " (only got ", (uint64_t)sb.st_size, ")");
int64_t len = count.small ? target_count : (int64_t)sb.st_size;
- return (List_t){.data=content, .atomic=1, .stride=1, .length=len};
+ return (List_t){.data = content, .atomic = 1, .stride = 1, .length = len};
} else {
size_t capacity = 256, len = 0;
char *content = GC_MALLOC_ATOMIC(capacity);
@@ -354,8 +343,7 @@ public OptionalList_t Path$read_bytes(Path_t path, OptionalInt_t count)
close(fd);
return NONE_LIST;
} else if (just_read == 0) {
- if (errno == EAGAIN || errno == EINTR)
- continue;
+ if (errno == EAGAIN || errno == EINTR) continue;
break;
}
count_remaining -= (int64_t)just_read;
@@ -370,19 +358,19 @@ public OptionalList_t Path$read_bytes(Path_t path, OptionalInt_t count)
close(fd);
if (count.small != 0 && (int64_t)len < target_count)
fail("Could not read ", target_count, " bytes from ", path, " (only got ", (uint64_t)len, ")");
- return (List_t){.data=content, .atomic=1, .stride=1, .length=(int64_t)len};
+ return (List_t){.data = content, .atomic = 1, .stride = 1, .length = (int64_t)len};
}
}
-public OptionalText_t Path$read(Path_t path)
-{
+public
+OptionalText_t Path$read(Path_t path) {
List_t bytes = Path$read_bytes(path, NONE_INT);
if (bytes.length < 0) return NONE_TEXT;
return Text$from_bytes(bytes);
}
-public OptionalText_t Path$owner(Path_t path, bool follow_symlinks)
-{
+public
+OptionalText_t Path$owner(Path_t path, bool follow_symlinks) {
struct stat sb;
int status = path_stat(path, follow_symlinks, &sb);
if (status != 0) return NONE_TEXT;
@@ -390,8 +378,8 @@ public OptionalText_t Path$owner(Path_t path, bool follow_symlinks)
return pw ? Text$from_str(pw->pw_name) : NONE_TEXT;
}
-public OptionalText_t Path$group(Path_t path, bool follow_symlinks)
-{
+public
+OptionalText_t Path$group(Path_t path, bool follow_symlinks) {
struct stat sb;
int status = path_stat(path, follow_symlinks, &sb);
if (status != 0) return NONE_TEXT;
@@ -399,8 +387,8 @@ public OptionalText_t Path$group(Path_t path, bool follow_symlinks)
return gr ? Text$from_str(gr->gr_name) : NONE_TEXT;
}
-public void Path$set_owner(Path_t path, OptionalText_t owner, OptionalText_t group, bool follow_symlinks)
-{
+public
+void Path$set_owner(Path_t path, OptionalText_t owner, OptionalText_t group, bool follow_symlinks) {
uid_t owner_id = (uid_t)-1;
if (owner.length >= 0) {
struct passwd *pwd = getpwnam(Text$as_c_string(owner));
@@ -416,38 +404,34 @@ public void Path$set_owner(Path_t path, OptionalText_t owner, OptionalText_t gro
}
const char *path_str = Path$as_c_string(path);
int result = follow_symlinks ? chown(path_str, owner_id, group_id) : lchown(path_str, owner_id, group_id);
- if (result < 0)
- fail("Could not set owner!");
+ if (result < 0) fail("Could not set owner!");
}
-static int _remove_files(const char *path, const struct stat *sbuf, int type, struct FTW *ftwb)
-{
+static int _remove_files(const char *path, const struct stat *sbuf, int type, struct FTW *ftwb) {
(void)sbuf, (void)ftwb;
switch (type) {
- case FTW_F: case FTW_SL: case FTW_SLN:
+ case FTW_F:
+ case FTW_SL:
+ case FTW_SLN:
if (remove(path) < 0) {
fail("Could not remove file: ", path, " (", strerror(errno), ")");
return -1;
}
return 0;
case FTW_DP:
- if (rmdir(path) != 0)
- fail("Could not remove directory: ", path, " (", strerror(errno), ")");
+ if (rmdir(path) != 0) fail("Could not remove directory: ", path, " (", strerror(errno), ")");
return 0;
- default:
- fail("Could not remove path: ", path, " (not a file or directory)");
- return -1;
+ default: fail("Could not remove path: ", path, " (not a file or directory)"); return -1;
}
}
-public void Path$remove(Path_t path, bool ignore_missing)
-{
+public
+void Path$remove(Path_t path, bool ignore_missing) {
path = Path$expand_home(path);
const char *path_str = Path$as_c_string(path);
struct stat sb;
if (lstat(path_str, &sb) != 0) {
- if (!ignore_missing)
- fail("Could not remove file: ", path_str, " (", strerror(errno), ")");
+ if (!ignore_missing) fail("Could not remove file: ", path_str, " (", strerror(errno), ")");
return;
}
@@ -456,48 +440,40 @@ public void Path$remove(Path_t path, bool ignore_missing)
fail("Could not remove file: ", path_str, " (", strerror(errno), ")");
} else if ((sb.st_mode & S_IFMT) == S_IFDIR) {
const int num_open_fd = 10;
- if (nftw(path_str, _remove_files, num_open_fd, FTW_DEPTH|FTW_MOUNT|FTW_PHYS) < 0)
+ if (nftw(path_str, _remove_files, num_open_fd, FTW_DEPTH | FTW_MOUNT | FTW_PHYS) < 0)
fail("Could not remove directory: %s (%s)", path_str, strerror(errno));
} else {
fail("Could not remove path: ", path_str, " (not a file or directory)");
}
}
-public void Path$create_directory(Path_t path, int permissions)
-{
+public
+void Path$create_directory(Path_t path, int permissions) {
path = Path$expand_home(path);
const char *c_path = Path$as_c_string(path);
int status = mkdir(c_path, (mode_t)permissions);
- if (status != 0 && errno != EEXIST)
- fail("Could not create directory: ", c_path, " (", strerror(errno), ")");
+ if (status != 0 && errno != EEXIST) fail("Could not create directory: ", c_path, " (", strerror(errno), ")");
}
-static List_t _filtered_children(Path_t path, bool include_hidden, mode_t filter)
-{
+static List_t _filtered_children(Path_t path, bool include_hidden, mode_t filter) {
path = Path$expand_home(path);
struct dirent *dir;
List_t children = {};
const char *path_str = Path$as_c_string(path);
size_t path_len = strlen(path_str);
DIR *d = opendir(path_str);
- if (!d)
- fail("Could not open directory: ", path, " (", strerror(errno), ")");
+ if (!d) fail("Could not open directory: ", path, " (", strerror(errno), ")");
- if (path_str[path_len-1] == '/')
- --path_len;
+ if (path_str[path_len - 1] == '/') --path_len;
while ((dir = readdir(d)) != NULL) {
- if (!include_hidden && dir->d_name[0] == '.')
- continue;
- if (streq(dir->d_name, ".") || streq(dir->d_name, ".."))
- continue;
+ if (!include_hidden && dir->d_name[0] == '.') continue;
+ if (streq(dir->d_name, ".") || streq(dir->d_name, "..")) continue;
const char *child_str = String(string_slice(path_str, path_len), "/", dir->d_name);
struct stat sb;
- if (stat(child_str, &sb) != 0)
- continue;
- if (!((sb.st_mode & S_IFMT) & filter))
- continue;
+ if (stat(child_str, &sb) != 0) continue;
+ if (!((sb.st_mode & S_IFMT) & filter)) continue;
Path_t child = Path$from_str(child_str);
List$insert(&children, &child, I(0), sizeof(Path_t));
@@ -506,23 +482,19 @@ static List_t _filtered_children(Path_t path, bool include_hidden, mode_t filter
return children;
}
-public List_t Path$children(Path_t path, bool include_hidden)
-{
- return _filtered_children(path, include_hidden, (mode_t)-1);
-}
+public
+List_t Path$children(Path_t path, bool include_hidden) { return _filtered_children(path, include_hidden, (mode_t)-1); }
-public List_t Path$files(Path_t path, bool include_hidden)
-{
- return _filtered_children(path, include_hidden, S_IFREG);
-}
+public
+List_t Path$files(Path_t path, bool include_hidden) { return _filtered_children(path, include_hidden, S_IFREG); }
-public List_t Path$subdirectories(Path_t path, bool include_hidden)
-{
+public
+List_t Path$subdirectories(Path_t path, bool include_hidden) {
return _filtered_children(path, include_hidden, S_IFDIR);
}
-public Path_t Path$unique_directory(Path_t path)
-{
+public
+Path_t Path$unique_directory(Path_t path) {
path = Path$expand_home(path);
const char *path_str = Path$as_c_string(path);
size_t len = strlen(path_str);
@@ -530,15 +502,14 @@ public Path_t Path$unique_directory(Path_t path)
char buf[PATH_MAX] = {};
memcpy(buf, path_str, len);
buf[len] = '\0';
- if (buf[len-1] == '/')
- buf[--len] = '\0';
+ if (buf[len - 1] == '/') buf[--len] = '\0';
char *created = mkdtemp(buf);
if (!created) fail("Failed to create temporary directory: ", path_str, " (", strerror(errno), ")");
return Path$from_str(created);
}
-public Path_t Path$write_unique_bytes(Path_t path, List_t bytes)
-{
+public
+Path_t Path$write_unique_bytes(Path_t path, List_t bytes) {
path = Path$expand_home(path);
const char *path_str = Path$as_c_string(path);
size_t len = strlen(path_str);
@@ -554,82 +525,73 @@ public Path_t Path$write_unique_bytes(Path_t path, List_t bytes)
++suffixlen;
int fd = mkstemps(buf, suffixlen);
- if (fd == -1)
- fail("Could not write to unique file: ", buf, "\n", strerror(errno));
+ if (fd == -1) fail("Could not write to unique file: ", buf, "\n", strerror(errno));
- if (bytes.stride != 1)
- List$compact(&bytes, 1);
+ if (bytes.stride != 1) List$compact(&bytes, 1);
ssize_t written = write(fd, bytes.data, (size_t)bytes.length);
- if (written != (ssize_t)bytes.length)
- fail("Could not write to file: ", buf, "\n", strerror(errno));
+ if (written != (ssize_t)bytes.length) fail("Could not write to file: ", buf, "\n", strerror(errno));
close(fd);
return Path$from_str(buf);
}
-public Path_t Path$write_unique(Path_t path, Text_t text)
-{
- return Path$write_unique_bytes(path, Text$utf8_bytes(text));
-}
+public
+Path_t Path$write_unique(Path_t path, Text_t text) { return Path$write_unique_bytes(path, Text$utf8_bytes(text)); }
-public Path_t Path$parent(Path_t path)
-{
+public
+Path_t Path$parent(Path_t path) {
if (path.type.$tag == PATH_ABSOLUTE && path.components.length == 0) {
return path;
- } else if (path.components.length > 0 && !Text$equal_values(*(Text_t*)(path.components.data + path.components.stride*(path.components.length-1)),
- Text(".."))) {
- return (Path_t){.type.$tag=path.type.$tag, .components=List$slice(path.components, I(1), I(-2))};
+ } else if (path.components.length > 0
+ && !Text$equal_values(
+ *(Text_t *)(path.components.data + path.components.stride * (path.components.length - 1)),
+ Text(".."))) {
+ return (Path_t){.type.$tag = path.type.$tag, .components = List$slice(path.components, I(1), I(-2))};
} else {
- Path_t result = {.type.$tag=path.type.$tag, .components=path.components};
+ Path_t result = {.type.$tag = path.type.$tag, .components = path.components};
LIST_INCREF(result.components);
List$insert_value(&result.components, Text(".."), I(0), sizeof(Text_t));
return result;
}
}
-public PUREFUNC Text_t Path$base_name(Path_t path)
-{
+public
+PUREFUNC Text_t Path$base_name(Path_t path) {
if (path.components.length >= 1)
- return *(Text_t*)(path.components.data + path.components.stride*(path.components.length-1));
- else if (path.type.$tag == PATH_HOME)
- return Text("~");
- else if (path.type.$tag == PATH_RELATIVE)
- return Text(".");
- else
- return EMPTY_TEXT;
+ return *(Text_t *)(path.components.data + path.components.stride * (path.components.length - 1));
+ else if (path.type.$tag == PATH_HOME) return Text("~");
+ else if (path.type.$tag == PATH_RELATIVE) return Text(".");
+ else return EMPTY_TEXT;
}
-public Text_t Path$extension(Path_t path, bool full)
-{
+public
+Text_t Path$extension(Path_t path, bool full) {
const char *base = Text$as_c_string(Path$base_name(path));
const char *dot = full ? strchr(base + 1, '.') : strrchr(base + 1, '.');
const char *extension = dot ? dot + 1 : "";
return Text$from_str(extension);
}
-public bool Path$has_extension(Path_t path, Text_t extension)
-{
- if (path.components.length < 2)
- return extension.length == 0;
+public
+bool Path$has_extension(Path_t path, Text_t extension) {
+ if (path.components.length < 2) return extension.length == 0;
- Text_t last = *(Text_t*)(path.components.data + path.components.stride*(path.components.length-1));
+ Text_t last = *(Text_t *)(path.components.data + path.components.stride * (path.components.length - 1));
if (extension.length == 0)
return !Text$has(Text$from(last, I(2)), Text(".")) || Text$equal_values(last, Text(".."));
- if (!Text$starts_with(extension, Text("."), NULL))
- extension = Texts(Text("."), extension);
+ if (!Text$starts_with(extension, Text("."), NULL)) extension = Texts(Text("."), extension);
return Text$ends_with(Text$from(last, I(2)), extension, NULL);
}
-public Path_t Path$child(Path_t path, Text_t name)
-{
- if (Text$has(name, Text("/")) || Text$has(name, Text(";")))
- fail("Path name has invalid characters: ", name);
+public
+Path_t Path$child(Path_t path, Text_t name) {
+ if (Text$has(name, Text("/")) || Text$has(name, Text(";"))) fail("Path name has invalid characters: ", name);
Path_t result = {
- .type.$tag=path.type.$tag,
- .components=path.components,
+ .type.$tag = path.type.$tag,
+ .components = path.components,
};
LIST_INCREF(result.components);
List$insert(&result.components, &name, I(0), sizeof(Text_t));
@@ -637,31 +599,27 @@ public Path_t Path$child(Path_t path, Text_t name)
return result;
}
-public Path_t Path$sibling(Path_t path, Text_t name)
-{
- return Path$child(Path$parent(path), name);
-}
+public
+Path_t Path$sibling(Path_t path, Text_t name) { return Path$child(Path$parent(path), name); }
-public Path_t Path$with_extension(Path_t path, Text_t extension, bool replace)
-{
- if (path.components.length == 0)
- fail("A path with no components can't have an extension!");
+public
+Path_t Path$with_extension(Path_t path, Text_t extension, bool replace) {
+ if (path.components.length == 0) fail("A path with no components can't have an extension!");
if (Text$has(extension, Text("/")) || Text$has(extension, Text(";")))
fail("Path extension has invalid characters: ", extension);
Path_t result = {
- .type.$tag=path.type.$tag,
- .components=path.components,
+ .type.$tag = path.type.$tag,
+ .components = path.components,
};
LIST_INCREF(result.components);
- Text_t last = *(Text_t*)(path.components.data + path.components.stride*(path.components.length-1));
+ Text_t last = *(Text_t *)(path.components.data + path.components.stride * (path.components.length - 1));
List$remove_at(&result.components, I(-1), I(1), sizeof(Text_t));
if (replace) {
const char *base = Text$as_c_string(last);
const char *dot = strchr(base + 1, '.');
- if (dot)
- last = Text$from_strn(base, (size_t)(dot - base));
+ if (dot) last = Text$from_strn(base, (size_t)(dot - base));
}
last = Text$concat(last, extension);
@@ -669,16 +627,14 @@ public Path_t Path$with_extension(Path_t path, Text_t extension, bool replace)
return result;
}
-static void _line_reader_cleanup(FILE **f)
-{
+static void _line_reader_cleanup(FILE **f) {
if (f && *f) {
fclose(*f);
*f = NULL;
}
}
-static Text_t _next_line(FILE **f)
-{
+static Text_t _next_line(FILE **f) {
if (!f || !*f) return NONE_TEXT;
char *line = NULL;
@@ -689,43 +645,41 @@ static Text_t _next_line(FILE **f)
return NONE_TEXT;
}
- while (len > 0 && (line[len-1] == '\r' || line[len-1] == '\n'))
+ while (len > 0 && (line[len - 1] == '\r' || line[len - 1] == '\n'))
--len;
- if (u8_check((uint8_t*)line, (size_t)len) != NULL)
- fail("Invalid UTF8!");
+ if (u8_check((uint8_t *)line, (size_t)len) != NULL) fail("Invalid UTF8!");
Text_t line_text = Text$from_strn(line, (size_t)len);
free(line);
return line_text;
}
-public OptionalClosure_t Path$by_line(Path_t path)
-{
+public
+OptionalClosure_t Path$by_line(Path_t path) {
path = Path$expand_home(path);
FILE *f = fopen(Path$as_c_string(path), "r");
- if (f == NULL)
- return NONE_CLOSURE;
+ if (f == NULL) return NONE_CLOSURE;
- FILE **wrapper = GC_MALLOC(sizeof(FILE*));
+ FILE **wrapper = GC_MALLOC(sizeof(FILE *));
*wrapper = f;
- GC_register_finalizer(wrapper, (void*)_line_reader_cleanup, NULL, NULL, NULL);
- return (Closure_t){.fn=(void*)_next_line, .userdata=wrapper};
+ GC_register_finalizer(wrapper, (void *)_line_reader_cleanup, NULL, NULL, NULL);
+ return (Closure_t){.fn = (void *)_next_line, .userdata = wrapper};
}
-public List_t Path$glob(Path_t path)
-{
+public
+List_t Path$glob(Path_t path) {
glob_t glob_result;
int status = glob(Path$as_c_string(path), GLOB_BRACE | GLOB_TILDE, NULL, &glob_result);
- if (status != 0 && status != GLOB_NOMATCH)
- fail("Failed to perform globbing");
+ if (status != 0 && status != GLOB_NOMATCH) fail("Failed to perform globbing");
List_t glob_files = {};
for (size_t i = 0; i < glob_result.gl_pathc; i++) {
size_t len = strlen(glob_result.gl_pathv[i]);
- if ((len >= 2 && glob_result.gl_pathv[i][len-1] == '.' && glob_result.gl_pathv[i][len-2] == '/')
- || (len >= 2 && glob_result.gl_pathv[i][len-1] == '.' && glob_result.gl_pathv[i][len-2] == '.' && glob_result.gl_pathv[i][len-3] == '/'))
+ if ((len >= 2 && glob_result.gl_pathv[i][len - 1] == '.' && glob_result.gl_pathv[i][len - 2] == '/')
+ || (len >= 2 && glob_result.gl_pathv[i][len - 1] == '.' && glob_result.gl_pathv[i][len - 2] == '.'
+ && glob_result.gl_pathv[i][len - 3] == '/'))
continue;
Path_t p = Path$from_str(glob_result.gl_pathv[i]);
List$insert(&glob_files, &p, I(0), sizeof(Path_t));
@@ -733,52 +687,51 @@ public List_t Path$glob(Path_t path)
return glob_files;
}
-public Path_t Path$current_dir(void)
-{
+public
+Path_t Path$current_dir(void) {
char cwd[PATH_MAX];
- if (getcwd(cwd, sizeof(cwd)) == NULL)
- fail("Could not get current working directory");
+ if (getcwd(cwd, sizeof(cwd)) == NULL) fail("Could not get current working directory");
return Path$from_str(cwd);
}
-public PUREFUNC uint64_t Path$hash(const void *obj, const TypeInfo_t *type)
-{
+public
+PUREFUNC uint64_t Path$hash(const void *obj, const TypeInfo_t *type) {
(void)type;
- Path_t *path = (Path_t*)obj;
+ Path_t *path = (Path_t *)obj;
siphash sh;
siphashinit(&sh, (uint64_t)path->type.$tag);
for (int64_t i = 0; i < path->components.length; i++) {
- uint64_t item_hash = Text$hash(path->components.data + i*path->components.stride, &Text$info);
+ uint64_t item_hash = Text$hash(path->components.data + i * path->components.stride, &Text$info);
siphashadd64bits(&sh, item_hash);
}
return siphashfinish_last_part(&sh, (uint64_t)path->components.length);
}
-public PUREFUNC int32_t Path$compare(const void *va, const void *vb, const TypeInfo_t *type)
-{
+public
+PUREFUNC int32_t Path$compare(const void *va, const void *vb, const TypeInfo_t *type) {
(void)type;
- Path_t *a = (Path_t*)va, *b = (Path_t*)vb;
+ Path_t *a = (Path_t *)va, *b = (Path_t *)vb;
int diff = ((int)a->type.$tag - (int)b->type.$tag);
if (diff != 0) return diff;
return List$compare(&a->components, &b->components, List$info(&Text$info));
}
-public PUREFUNC bool Path$equal(const void *va, const void *vb, const TypeInfo_t *type)
-{
+public
+PUREFUNC bool Path$equal(const void *va, const void *vb, const TypeInfo_t *type) {
(void)type;
- Path_t *a = (Path_t*)va, *b = (Path_t*)vb;
+ Path_t *a = (Path_t *)va, *b = (Path_t *)vb;
if (a->type.$tag != b->type.$tag) return false;
return List$equal(&a->components, &b->components, List$info(&Text$info));
}
-public PUREFUNC bool Path$equal_values(Path_t a, Path_t b)
-{
+public
+PUREFUNC bool Path$equal_values(Path_t a, Path_t b) {
if (a.type.$tag != b.type.$tag) return false;
return List$equal(&a.components, &b.components, List$info(&Text$info));
}
-public int Path$print(FILE *f, Path_t path)
-{
+public
+int Path$print(FILE *f, Path_t path) {
if (path.components.length == 0) {
if (path.type.$tag == PATH_ABSOLUTE) return fputs("/", f);
else if (path.type.$tag == PATH_RELATIVE) return fputs(".", f);
@@ -791,91 +744,86 @@ public int Path$print(FILE *f, Path_t path)
} else if (path.type.$tag == PATH_HOME) {
n += fputs("~/", f);
} else if (path.type.$tag == PATH_RELATIVE) {
- if (!Text$equal_values(*(Text_t*)path.components.data, Text("..")))
- n += fputs("./", f);
+ if (!Text$equal_values(*(Text_t *)path.components.data, Text(".."))) n += fputs("./", f);
}
for (int64_t i = 0; i < path.components.length; i++) {
- Text_t *comp = (Text_t*)(path.components.data + i*path.components.stride);
+ Text_t *comp = (Text_t *)(path.components.data + i * path.components.stride);
n += Text$print(f, *comp);
- if (i + 1 < path.components.length)
- n += fputc('/', f);
+ if (i + 1 < path.components.length) n += fputc('/', f);
}
return n;
}
-public const char *Path$as_c_string(Path_t path)
-{
- return String(path);
-}
+public
+const char *Path$as_c_string(Path_t path) { return String(path); }
-public Text_t Path$as_text(const void *obj, bool color, const TypeInfo_t *type)
-{
+public
+Text_t Path$as_text(const void *obj, bool color, const TypeInfo_t *type) {
(void)type;
if (!obj) return Text("Path");
- Path_t *path = (Path_t*)obj;
+ Path_t *path = (Path_t *)obj;
Text_t text = Text$join(Text("/"), path->components);
- if (path->type.$tag == PATH_HOME)
- text = Text$concat(path->components.length > 0 ? Text("~/") : Text("~"), text);
- else if (path->type.$tag == PATH_ABSOLUTE)
- text = Text$concat(Text("/"), text);
- else if (path->type.$tag == PATH_RELATIVE && (path->components.length == 0 || !Text$equal_values(*(Text_t*)(path->components.data), Text(".."))))
+ if (path->type.$tag == PATH_HOME) text = Text$concat(path->components.length > 0 ? Text("~/") : Text("~"), text);
+ else if (path->type.$tag == PATH_ABSOLUTE) text = Text$concat(Text("/"), text);
+ else if (path->type.$tag == PATH_RELATIVE
+ && (path->components.length == 0 || !Text$equal_values(*(Text_t *)(path->components.data), Text(".."))))
text = Text$concat(path->components.length > 0 ? Text("./") : Text("."), text);
- if (color)
- text = Texts(Text("\033[32;1m"), text, Text("\033[m"));
+ if (color) text = Texts(Text("\033[32;1m"), text, Text("\033[m"));
return text;
}
-public CONSTFUNC bool Path$is_none(const void *obj, const TypeInfo_t *type)
-{
+public
+CONSTFUNC bool Path$is_none(const void *obj, const TypeInfo_t *type) {
(void)type;
- return ((Path_t*)obj)->type.$tag == PATH_NONE;
+ return ((Path_t *)obj)->type.$tag == PATH_NONE;
}
-public void Path$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type)
-{
+public
+void Path$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type) {
(void)type;
- Path_t *path = (Path_t*)obj;
+ Path_t *path = (Path_t *)obj;
fputc((int)path->type.$tag, out);
List$serialize(&path->components, out, pointers, List$info(&Text$info));
}
-public void Path$deserialize(FILE *in, void *obj, List_t *pointers, const TypeInfo_t *type)
-{
+public
+void Path$deserialize(FILE *in, void *obj, List_t *pointers, const TypeInfo_t *type) {
(void)type;
Path_t path = {};
path.type.$tag = fgetc(in);
List$deserialize(in, &path.components, pointers, List$info(&Text$info));
- *(Path_t*)obj = path;
-}
-
-public const TypeInfo_t Path$info = {
- .size=sizeof(Path_t),
- .align=__alignof__(Path_t),
- .tag=OpaqueInfo,
- .metamethods={
- .as_text=Path$as_text,
- .hash=Path$hash,
- .compare=Path$compare,
- .equal=Path$equal,
- .is_none=Path$is_none,
- .serialize=Path$serialize,
- .deserialize=Path$deserialize,
- }
-};
-
-public const TypeInfo_t PathType$info = {
- .size=sizeof(PathType_t),
- .align=__alignof__(PathType_t),
- .metamethods=PackedDataEnum$metamethods,
- .tag=EnumInfo,
- .EnumInfo={
- .name="PathType",
- .num_tags=3,
- .tags=((NamedType_t[3]){{.name="Relative"}, {.name="Absolute"}, {.name="Home"}}),
- },
+ *(Path_t *)obj = path;
+}
+
+public
+const TypeInfo_t Path$info = {.size = sizeof(Path_t),
+ .align = __alignof__(Path_t),
+ .tag = OpaqueInfo,
+ .metamethods = {
+ .as_text = Path$as_text,
+ .hash = Path$hash,
+ .compare = Path$compare,
+ .equal = Path$equal,
+ .is_none = Path$is_none,
+ .serialize = Path$serialize,
+ .deserialize = Path$deserialize,
+ }};
+
+public
+const TypeInfo_t PathType$info = {
+ .size = sizeof(PathType_t),
+ .align = __alignof__(PathType_t),
+ .metamethods = PackedDataEnum$metamethods,
+ .tag = EnumInfo,
+ .EnumInfo =
+ {
+ .name = "PathType",
+ .num_tags = 3,
+ .tags = ((NamedType_t[3]){{.name = "Relative"}, {.name = "Absolute"}, {.name = "Home"}}),
+ },
};
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/stdlib/paths.h b/src/stdlib/paths.h
index 6284e55b..7f0d8830 100644
--- a/src/stdlib/paths.h
+++ b/src/stdlib/paths.h
@@ -15,7 +15,7 @@ Path_t Path$from_text(Text_t text);
const char *Path$as_c_string(Path_t path);
#define Path(str) Path$from_str(str)
Path_t Path$_concat(int n, Path_t items[n]);
-#define Path$concat(...) Path$_concat((int)sizeof((Path_t[]){__VA_ARGS__})/sizeof(Path_t), ((Path_t[]){__VA_ARGS__}))
+#define Path$concat(...) Path$_concat((int)sizeof((Path_t[]){__VA_ARGS__}) / sizeof(Path_t), ((Path_t[]){__VA_ARGS__}))
Path_t Path$resolved(Path_t path, Path_t relative_to);
Path_t Path$relative_to(Path_t path, Path_t relative_to);
Path_t Path$expand_home(Path_t path);
@@ -59,7 +59,7 @@ Path_t Path$current_dir(void);
Closure_t Path$by_line(Path_t path);
List_t Path$glob(Path_t path);
-uint64_t Path$hash(const void *obj, const TypeInfo_t*);
+uint64_t Path$hash(const void *obj, const TypeInfo_t *);
int32_t Path$compare(const void *a, const void *b, const TypeInfo_t *type);
bool Path$equal(const void *a, const void *b, const TypeInfo_t *type);
bool Path$equal_values(Path_t a, Path_t b);
@@ -72,4 +72,3 @@ extern const TypeInfo_t Path$info;
extern const TypeInfo_t PathType$info;
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
-
diff --git a/src/stdlib/pointers.c b/src/stdlib/pointers.c
index 3708da62..e94ede6d 100644
--- a/src/stdlib/pointers.c
+++ b/src/stdlib/pointers.c
@@ -13,22 +13,19 @@
#include "types.h"
#include "util.h"
-public Text_t Pointer$as_text(const void *x, bool colorize, const TypeInfo_t *type) {
+public
+Text_t Pointer$as_text(const void *x, bool colorize, const TypeInfo_t *type) {
__typeof(type->PointerInfo) ptr_info = type->PointerInfo;
if (!x) {
Text_t typename = generic_as_text(NULL, false, ptr_info.pointed);
- if (colorize)
- return Text$concat(Text("\x1b[34;1m"), Text$from_str(ptr_info.sigil), typename, Text("\x1b[m"));
- else
- return Text$concat(Text$from_str(ptr_info.sigil), typename);
+ if (colorize) return Text$concat(Text("\x1b[34;1m"), Text$from_str(ptr_info.sigil), typename, Text("\x1b[m"));
+ else return Text$concat(Text$from_str(ptr_info.sigil), typename);
}
- const void *ptr = *(const void**)x;
+ const void *ptr = *(const void **)x;
if (!ptr) {
Text_t typename = generic_as_text(NULL, false, ptr_info.pointed);
- if (colorize)
- return Text$concat(Text("\x1b[34;1m!"), typename, Text("\x1b[m"));
- else
- return Text$concat(Text("!"), typename);
+ if (colorize) return Text$concat(Text("\x1b[34;1m!"), typename, Text("\x1b[m"));
+ else return Text$concat(Text("!"), typename);
}
static const void *root = NULL;
@@ -61,38 +58,38 @@ public Text_t Pointer$as_text(const void *x, bool colorize, const TypeInfo_t *ty
}
Text_t text;
- if (colorize)
- text = Text$concat(Text("\x1b[34;1m"), Text$from_str(ptr_info.sigil), Text("\x1b[m"), pointed);
- else
- text = Text$concat(Text$from_str(ptr_info.sigil), pointed);
+ if (colorize) text = Text$concat(Text("\x1b[34;1m"), Text$from_str(ptr_info.sigil), Text("\x1b[m"), pointed);
+ else text = Text$concat(Text$from_str(ptr_info.sigil), pointed);
return text;
}
PUREFUNC public int32_t Pointer$compare(const void *x, const void *y, const TypeInfo_t *info) {
(void)info;
- const void *xp = *(const void**)x, *yp = *(const void**)y;
+ const void *xp = *(const void **)x, *yp = *(const void **)y;
return (xp > yp) - (xp < yp);
}
PUREFUNC public bool Pointer$equal(const void *x, const void *y, const TypeInfo_t *info) {
(void)info;
- const void *xp = *(const void**)x, *yp = *(const void**)y;
+ const void *xp = *(const void **)x, *yp = *(const void **)y;
return xp == yp;
}
-PUREFUNC public bool Pointer$is_none(const void *x, const TypeInfo_t *info)
-{
+PUREFUNC public bool Pointer$is_none(const void *x, const TypeInfo_t *info) {
(void)info;
- return *(void**)x == NULL;
+ return *(void **)x == NULL;
}
-public void Pointer$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type)
-{
- void *ptr = *(void**)obj;
+public
+void Pointer$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type) {
+ void *ptr = *(void **)obj;
assert(ptr != NULL);
- const TypeInfo_t ptr_to_int_table = {.size=sizeof(Table_t), .align=__alignof__(Table_t),
- .tag=TableInfo, .TableInfo.key=type, .TableInfo.value=&Int64$info};
+ const TypeInfo_t ptr_to_int_table = {.size = sizeof(Table_t),
+ .align = __alignof__(Table_t),
+ .tag = TableInfo,
+ .TableInfo.key = type,
+ .TableInfo.value = &Int64$info};
int64_t *id_ptr = Table$get(*pointers, &ptr, &ptr_to_int_table);
int64_t id;
@@ -105,23 +102,22 @@ public void Pointer$serialize(const void *obj, FILE *out, Table_t *pointers, con
Int64$serialize(&id, out, pointers, &Int64$info);
- if (!id_ptr)
- _serialize(ptr, out, pointers, type->PointerInfo.pointed);
+ if (!id_ptr) _serialize(ptr, out, pointers, type->PointerInfo.pointed);
}
-public void Pointer$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *type)
-{
+public
+void Pointer$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *type) {
int64_t id = 0;
Int64$deserialize(in, &id, pointers, &Int64$info);
assert(id != 0);
if (id > pointers->length) {
void *obj = GC_MALLOC((size_t)type->PointerInfo.pointed->size);
- List$insert(pointers, &obj, I(0), sizeof(void*));
+ List$insert(pointers, &obj, I(0), sizeof(void *));
_deserialize(in, obj, pointers, type->PointerInfo.pointed);
- *(void**)outval = obj;
+ *(void **)outval = obj;
} else {
- *(void**)outval = *(void**)(pointers->data + (id-1)*pointers->stride);
+ *(void **)outval = *(void **)(pointers->data + (id - 1) * pointers->stride);
}
}
diff --git a/src/stdlib/pointers.h b/src/stdlib/pointers.h
index 001dc5ce..522a97be 100644
--- a/src/stdlib/pointers.h
+++ b/src/stdlib/pointers.h
@@ -12,25 +12,33 @@
Text_t Pointer$as_text(const void *x, bool colorize, const TypeInfo_t *type);
PUREFUNC int32_t Pointer$compare(const void *x, const void *y, const TypeInfo_t *type);
PUREFUNC bool Pointer$equal(const void *x, const void *y, const TypeInfo_t *type);
-PUREFUNC bool Pointer$is_none(const void *x, const TypeInfo_t*);
+PUREFUNC bool Pointer$is_none(const void *x, const TypeInfo_t *);
void Pointer$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type);
void Pointer$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *type);
-#define Null(t) (t*)NULL
-#define POINTER_TYPE(_sigil, _pointed) (&(TypeInfo_t){\
- .size=sizeof(void*), .align=__alignof__(void*), .tag=PointerInfo, .PointerInfo.sigil=_sigil, .PointerInfo.pointed=_pointed})
-
-#define Pointer$metamethods { \
- .as_text=Pointer$as_text, \
- .compare=Pointer$compare, \
- .equal=Pointer$equal, \
- .is_none=Pointer$is_none, \
- .serialize=Pointer$serialize, \
- .deserialize=Pointer$deserialize, \
-}
-
-#define Pointer$info(sigil_expr, pointed_info) &((TypeInfo_t){.size=sizeof(void*), .align=__alignof__(void*), \
- .tag=PointerInfo, .PointerInfo={.sigil=sigil_expr, .pointed=pointed_info}, \
- .metamethods=Pointer$metamethods})
+#define Null(t) (t *)NULL
+#define POINTER_TYPE(_sigil, _pointed) \
+ (&(TypeInfo_t){.size = sizeof(void *), \
+ .align = __alignof__(void *), \
+ .tag = PointerInfo, \
+ .PointerInfo.sigil = _sigil, \
+ .PointerInfo.pointed = _pointed})
+
+#define Pointer$metamethods \
+ { \
+ .as_text = Pointer$as_text, \
+ .compare = Pointer$compare, \
+ .equal = Pointer$equal, \
+ .is_none = Pointer$is_none, \
+ .serialize = Pointer$serialize, \
+ .deserialize = Pointer$deserialize, \
+ }
+
+#define Pointer$info(sigil_expr, pointed_info) \
+ &((TypeInfo_t){.size = sizeof(void *), \
+ .align = __alignof__(void *), \
+ .tag = PointerInfo, \
+ .PointerInfo = {.sigil = sigil_expr, .pointed = pointed_info}, \
+ .metamethods = Pointer$metamethods})
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/stdlib/powers.h b/src/stdlib/powers.h
index d1829b60..e9b6a74e 100644
--- a/src/stdlib/powers.h
+++ b/src/stdlib/powers.h
@@ -4,13 +4,12 @@
#include <stdint.h>
-#define npowers 87
-#define steppowers 8
+#define npowers 87
+#define steppowers 8
#define firstpower -348 /* 10 ^ -348 */
-#define expmax -32
-#define expmin -60
-
+#define expmax -32
+#define expmin -60
typedef struct Fp {
uint64_t frac;
@@ -18,54 +17,37 @@ typedef struct Fp {
} Fp;
static const Fp powers_ten[] = {
- { 18054884314459144840U, -1220 }, { 13451937075301367670U, -1193 },
- { 10022474136428063862U, -1166 }, { 14934650266808366570U, -1140 },
- { 11127181549972568877U, -1113 }, { 16580792590934885855U, -1087 },
- { 12353653155963782858U, -1060 }, { 18408377700990114895U, -1034 },
- { 13715310171984221708U, -1007 }, { 10218702384817765436U, -980 },
- { 15227053142812498563U, -954 }, { 11345038669416679861U, -927 },
- { 16905424996341287883U, -901 }, { 12595523146049147757U, -874 },
- { 9384396036005875287U, -847 }, { 13983839803942852151U, -821 },
- { 10418772551374772303U, -794 }, { 15525180923007089351U, -768 },
- { 11567161174868858868U, -741 }, { 17236413322193710309U, -715 },
- { 12842128665889583758U, -688 }, { 9568131466127621947U, -661 },
- { 14257626930069360058U, -635 }, { 10622759856335341974U, -608 },
- { 15829145694278690180U, -582 }, { 11793632577567316726U, -555 },
- { 17573882009934360870U, -529 }, { 13093562431584567480U, -502 },
- { 9755464219737475723U, -475 }, { 14536774485912137811U, -449 },
- { 10830740992659433045U, -422 }, { 16139061738043178685U, -396 },
- { 12024538023802026127U, -369 }, { 17917957937422433684U, -343 },
- { 13349918974505688015U, -316 }, { 9946464728195732843U, -289 },
- { 14821387422376473014U, -263 }, { 11042794154864902060U, -236 },
- { 16455045573212060422U, -210 }, { 12259964326927110867U, -183 },
- { 18268770466636286478U, -157 }, { 13611294676837538539U, -130 },
- { 10141204801825835212U, -103 }, { 15111572745182864684U, -77 },
- { 11258999068426240000U, -50 }, { 16777216000000000000U, -24 },
- { 12500000000000000000U, 3 }, { 9313225746154785156U, 30 },
- { 13877787807814456755U, 56 }, { 10339757656912845936U, 83 },
- { 15407439555097886824U, 109 }, { 11479437019748901445U, 136 },
- { 17105694144590052135U, 162 }, { 12744735289059618216U, 189 },
- { 9495567745759798747U, 216 }, { 14149498560666738074U, 242 },
- { 10542197943230523224U, 269 }, { 15709099088952724970U, 295 },
- { 11704190886730495818U, 322 }, { 17440603504673385349U, 348 },
- { 12994262207056124023U, 375 }, { 9681479787123295682U, 402 },
- { 14426529090290212157U, 428 }, { 10748601772107342003U, 455 },
- { 16016664761464807395U, 481 }, { 11933345169920330789U, 508 },
- { 17782069995880619868U, 534 }, { 13248674568444952270U, 561 },
- { 9871031767461413346U, 588 }, { 14708983551653345445U, 614 },
- { 10959046745042015199U, 641 }, { 16330252207878254650U, 667 },
- { 12166986024289022870U, 694 }, { 18130221999122236476U, 720 },
- { 13508068024458167312U, 747 }, { 10064294952495520794U, 774 },
- { 14996968138956309548U, 800 }, { 11173611982879273257U, 827 },
- { 16649979327439178909U, 853 }, { 12405201291620119593U, 880 },
- { 9242595204427927429U, 907 }, { 13772540099066387757U, 933 },
- { 10261342003245940623U, 960 }, { 15290591125556738113U, 986 },
- { 11392378155556871081U, 1013 }, { 16975966327722178521U, 1039 },
- { 12648080533535911531U, 1066 }
-};
+ {18054884314459144840U, -1220}, {13451937075301367670U, -1193}, {10022474136428063862U, -1166},
+ {14934650266808366570U, -1140}, {11127181549972568877U, -1113}, {16580792590934885855U, -1087},
+ {12353653155963782858U, -1060}, {18408377700990114895U, -1034}, {13715310171984221708U, -1007},
+ {10218702384817765436U, -980}, {15227053142812498563U, -954}, {11345038669416679861U, -927},
+ {16905424996341287883U, -901}, {12595523146049147757U, -874}, {9384396036005875287U, -847},
+ {13983839803942852151U, -821}, {10418772551374772303U, -794}, {15525180923007089351U, -768},
+ {11567161174868858868U, -741}, {17236413322193710309U, -715}, {12842128665889583758U, -688},
+ {9568131466127621947U, -661}, {14257626930069360058U, -635}, {10622759856335341974U, -608},
+ {15829145694278690180U, -582}, {11793632577567316726U, -555}, {17573882009934360870U, -529},
+ {13093562431584567480U, -502}, {9755464219737475723U, -475}, {14536774485912137811U, -449},
+ {10830740992659433045U, -422}, {16139061738043178685U, -396}, {12024538023802026127U, -369},
+ {17917957937422433684U, -343}, {13349918974505688015U, -316}, {9946464728195732843U, -289},
+ {14821387422376473014U, -263}, {11042794154864902060U, -236}, {16455045573212060422U, -210},
+ {12259964326927110867U, -183}, {18268770466636286478U, -157}, {13611294676837538539U, -130},
+ {10141204801825835212U, -103}, {15111572745182864684U, -77}, {11258999068426240000U, -50},
+ {16777216000000000000U, -24}, {12500000000000000000U, 3}, {9313225746154785156U, 30},
+ {13877787807814456755U, 56}, {10339757656912845936U, 83}, {15407439555097886824U, 109},
+ {11479437019748901445U, 136}, {17105694144590052135U, 162}, {12744735289059618216U, 189},
+ {9495567745759798747U, 216}, {14149498560666738074U, 242}, {10542197943230523224U, 269},
+ {15709099088952724970U, 295}, {11704190886730495818U, 322}, {17440603504673385349U, 348},
+ {12994262207056124023U, 375}, {9681479787123295682U, 402}, {14426529090290212157U, 428},
+ {10748601772107342003U, 455}, {16016664761464807395U, 481}, {11933345169920330789U, 508},
+ {17782069995880619868U, 534}, {13248674568444952270U, 561}, {9871031767461413346U, 588},
+ {14708983551653345445U, 614}, {10959046745042015199U, 641}, {16330252207878254650U, 667},
+ {12166986024289022870U, 694}, {18130221999122236476U, 720}, {13508068024458167312U, 747},
+ {10064294952495520794U, 774}, {14996968138956309548U, 800}, {11173611982879273257U, 827},
+ {16649979327439178909U, 853}, {12405201291620119593U, 880}, {9242595204427927429U, 907},
+ {13772540099066387757U, 933}, {10261342003245940623U, 960}, {15290591125556738113U, 986},
+ {11392378155556871081U, 1013}, {16975966327722178521U, 1039}, {12648080533535911531U, 1066}};
-static Fp find_cachedpow10(int exp, int* k)
-{
+static Fp find_cachedpow10(int exp, int *k) {
const double one_log_ten = 0.30102999566398114;
int approx = -(exp + npowers) * one_log_ten;
diff --git a/src/stdlib/print.c b/src/stdlib/print.c
index 8e2dd862..d246c9c3 100644
--- a/src/stdlib/print.c
+++ b/src/stdlib/print.c
@@ -8,9 +8,9 @@
#include "print.h"
#include "util.h"
-public int _print_int(FILE *f, int64_t n)
-{
- char buf[21] = {[20]=0}; // Big enough for INT64_MIN + '\0'
+public
+int _print_int(FILE *f, int64_t n) {
+ char buf[21] = {[20] = 0}; // Big enough for INT64_MIN + '\0'
char *p = &buf[19];
bool negative = n < 0;
@@ -19,15 +19,14 @@ public int _print_int(FILE *f, int64_t n)
n /= 10;
} while (n > 0);
- if (negative)
- *(p--) = '-';
+ if (negative) *(p--) = '-';
return fwrite(p + 1, sizeof(char), (size_t)(&buf[19] - p), f);
}
-public int _print_uint(FILE *f, uint64_t n)
-{
- char buf[21] = {[20]=0}; // Big enough for UINT64_MAX + '\0'
+public
+int _print_uint(FILE *f, uint64_t n) {
+ char buf[21] = {[20] = 0}; // Big enough for UINT64_MAX + '\0'
char *p = &buf[19];
do {
@@ -38,8 +37,8 @@ public int _print_uint(FILE *f, uint64_t n)
return fwrite(p + 1, sizeof(char), (size_t)(&buf[19] - p), f);
}
-public int _print_hex(FILE *f, hex_format_t hex)
-{
+public
+int _print_hex(FILE *f, hex_format_t hex) {
int printed = 0;
if (!hex.no_prefix) printed += fputs("0x", f);
if (hex.digits > 0) {
@@ -50,24 +49,21 @@ public int _print_hex(FILE *f, hex_format_t hex)
printed += fputc('0', f);
}
}
- char buf[9] = {[8]='\0'}; // Enough space for FFFFFFFF + '\0'
+ char buf[9] = {[8] = '\0'}; // Enough space for FFFFFFFF + '\0'
char *p = &buf[7];
do {
uint8_t digit = hex.n % 16;
- if (digit <= 9)
- *(p--) = '0' + digit;
- else if (hex.uppercase)
- *(p--) = 'A' + digit - 10;
- else
- *(p--) = 'a' + digit - 10;
+ if (digit <= 9) *(p--) = '0' + digit;
+ else if (hex.uppercase) *(p--) = 'A' + digit - 10;
+ else *(p--) = 'a' + digit - 10;
hex.n /= 16;
} while (hex.n > 0);
printed += (int)fwrite(p + 1, sizeof(char), (size_t)(&buf[7] - p), f);
return printed;
}
-public int _print_oct(FILE *f, oct_format_t oct)
-{
+public
+int _print_oct(FILE *f, oct_format_t oct) {
int printed = 0;
if (!oct.no_prefix) printed += fputs("0o", f);
if (oct.digits > 0) {
@@ -76,7 +72,7 @@ public int _print_oct(FILE *f, oct_format_t oct)
for (; oct.digits > 0; oct.digits -= 1)
printed += fputc('0', f);
}
- char buf[12] = {[11]='\0'}; // Enough space for octal UINT64_MAX + '\0'
+ char buf[12] = {[11] = '\0'}; // Enough space for octal UINT64_MAX + '\0'
char *p = &buf[10];
do {
*(p--) = '0' + (oct.n % 8);
@@ -86,25 +82,24 @@ public int _print_oct(FILE *f, oct_format_t oct)
return printed;
}
-public int _print_double(FILE *f, double n)
-{
+public
+int _print_double(FILE *f, double n) {
static char buf[24];
int len = fpconv_dtoa(n, buf);
return (int)fwrite(buf, sizeof(char), (size_t)len, f);
}
-public int _print_hex_double(FILE *f, hex_double_t hex)
-{
- if (hex.d != hex.d)
- return fputs("NAN", f);
- else if (hex.d == 1.0/0.0)
- return fputs("INF", f);
- else if (hex.d == -1.0/0.0)
- return fputs("-INF", f);
- else if (hex.d == 0.0)
- return fputs("0.0", f);
+public
+int _print_hex_double(FILE *f, hex_double_t hex) {
+ if (hex.d != hex.d) return fputs("NAN", f);
+ else if (hex.d == 1.0 / 0.0) return fputs("INF", f);
+ else if (hex.d == -1.0 / 0.0) return fputs("-INF", f);
+ else if (hex.d == 0.0) return fputs("0.0", f);
- union { double d; uint64_t u; } bits = { .d = hex.d };
+ union {
+ double d;
+ uint64_t u;
+ } bits = {.d = hex.d};
int sign = (bits.u >> 63) & 1ull;
int exp = (int)((bits.u >> 52) & 0x7FF) - 1023ull;
@@ -161,30 +156,27 @@ public int _print_hex_double(FILE *f, hex_double_t hex)
return fwrite(buf, sizeof(char), (size_t)(p - buf), f);
}
-public int _print_char(FILE *f, char c)
-{
+public
+int _print_char(FILE *f, char c) {
#define ESC(e) "'\\" e "'"
- const char *named[256] = {['\'']=ESC("'"), ['\\']=ESC("\\"),
- ['\n']=ESC("n"), ['\t']=ESC("t"), ['\r']=ESC("r"),
- ['\033']=ESC("e"), ['\v']=ESC("v"), ['\a']=ESC("a"), ['\b']=ESC("b")};
+ const char *named[256] = {
+ ['\''] = ESC("'"), ['\\'] = ESC("\\"), ['\n'] = ESC("n"), ['\t'] = ESC("t"), ['\r'] = ESC("r"),
+ ['\033'] = ESC("e"), ['\v'] = ESC("v"), ['\a'] = ESC("a"), ['\b'] = ESC("b")};
const char *name = named[(uint8_t)c];
- if (name != NULL)
- return fputs(name, f);
- else if (isprint(c))
-
- return fputc('\'', f) + fputc(c, f) + fputc('\'', f);
+ if (name != NULL) return fputs(name, f);
+ else if (isprint(c)) return fputc('\'', f) + fputc(c, f) + fputc('\'', f);
else
- return (fputs("'\\x", f) + _print_hex(f, hex((uint64_t)c, .digits=2, .no_prefix=true, .uppercase=true))
+ return (fputs("'\\x", f) + _print_hex(f, hex((uint64_t)c, .digits = 2, .no_prefix = true, .uppercase = true))
+ fputs("'", f));
#undef ESC
}
-public int _print_quoted(FILE *f, quoted_t quoted)
-{
+public
+int _print_quoted(FILE *f, quoted_t quoted) {
#define ESC(e) "\\" e
- const char *named[256] = {['"']=ESC("\""), ['\\']=ESC("\\"),
- ['\n']=ESC("n"), ['\t']=ESC("t"), ['\r']=ESC("r"),
- ['\033']=ESC("e"), ['\v']=ESC("v"), ['\a']=ESC("a"), ['\b']=ESC("b")};
+ const char *named[256] = {
+ ['"'] = ESC("\""), ['\\'] = ESC("\\"), ['\n'] = ESC("n"), ['\t'] = ESC("t"), ['\r'] = ESC("r"),
+ ['\033'] = ESC("e"), ['\v'] = ESC("v"), ['\a'] = ESC("a"), ['\b'] = ESC("b")};
int printed = fputc('"', f);
for (const char *p = quoted.str; *p; p++) {
const char *name = named[(uint8_t)*p];
@@ -193,7 +185,8 @@ public int _print_quoted(FILE *f, quoted_t quoted)
} else if (isprint(*p) || (uint8_t)*p > 0x7F) {
printed += fputc(*p, f);
} else {
- printed += fputs("\\x", f) + _print_hex(f, hex((uint64_t)*p, .digits=2, .no_prefix=true, .uppercase=true));
+ printed +=
+ fputs("\\x", f) + _print_hex(f, hex((uint64_t)*p, .digits = 2, .no_prefix = true, .uppercase = true));
}
}
printed += fputc('"', f);
@@ -202,52 +195,56 @@ public int _print_quoted(FILE *f, quoted_t quoted)
}
#if defined(__GLIBC__) && defined(_GNU_SOURCE)
- // GLIBC has fopencookie()
- static ssize_t _gc_stream_write(void *cookie, const char *buf, size_t size) {
- gc_stream_t *stream = (gc_stream_t *)cookie;
- if (stream->position + size + 1 > *stream->size)
- *stream->buffer = GC_REALLOC(*stream->buffer, (*stream->size += MAX(MAX(16UL, *stream->size/2UL), size + 1UL)));
- memcpy(&(*stream->buffer)[stream->position], buf, size);
- stream->position += size;
- (*stream->buffer)[stream->position] = '\0';
- return (ssize_t)size;
- }
+// GLIBC has fopencookie()
+static ssize_t _gc_stream_write(void *cookie, const char *buf, size_t size) {
+ gc_stream_t *stream = (gc_stream_t *)cookie;
+ if (stream->position + size + 1 > *stream->size)
+ *stream->buffer =
+ GC_REALLOC(*stream->buffer, (*stream->size += MAX(MAX(16UL, *stream->size / 2UL), size + 1UL)));
+ memcpy(&(*stream->buffer)[stream->position], buf, size);
+ stream->position += size;
+ (*stream->buffer)[stream->position] = '\0';
+ return (ssize_t)size;
+}
- public FILE *gc_memory_stream(char **buf, size_t *size) {
- gc_stream_t *stream = GC_MALLOC(sizeof(gc_stream_t));
- stream->size = size;
- stream->buffer = buf;
- *stream->size = 16;
- *stream->buffer = GC_MALLOC_ATOMIC(*stream->size);
- (*stream->buffer)[0] = '\0';
- stream->position = 0;
- cookie_io_functions_t functions = {.write = _gc_stream_write};
- return fopencookie(stream, "w", functions);
- }
+public
+FILE *gc_memory_stream(char **buf, size_t *size) {
+ gc_stream_t *stream = GC_MALLOC(sizeof(gc_stream_t));
+ stream->size = size;
+ stream->buffer = buf;
+ *stream->size = 16;
+ *stream->buffer = GC_MALLOC_ATOMIC(*stream->size);
+ (*stream->buffer)[0] = '\0';
+ stream->position = 0;
+ cookie_io_functions_t functions = {.write = _gc_stream_write};
+ return fopencookie(stream, "w", functions);
+}
#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
- // BSDs have funopen() and fwopen()
- static int _gc_stream_write(void *cookie, const char *buf, int size) {
- gc_stream_t *stream = (gc_stream_t *)cookie;
- if (stream->position + size + 1 > *stream->size)
- *stream->buffer = GC_REALLOC(*stream->buffer, (*stream->size += MAX(MAX(16UL, *stream->size/2UL), size + 1UL)));
- memcpy(&(*stream->buffer)[stream->position], buf, size);
- stream->position += size;
- (*stream->buffer)[stream->position] = '\0';
- return size;
- }
+// BSDs have funopen() and fwopen()
+static int _gc_stream_write(void *cookie, const char *buf, int size) {
+ gc_stream_t *stream = (gc_stream_t *)cookie;
+ if (stream->position + size + 1 > *stream->size)
+ *stream->buffer =
+ GC_REALLOC(*stream->buffer, (*stream->size += MAX(MAX(16UL, *stream->size / 2UL), size + 1UL)));
+ memcpy(&(*stream->buffer)[stream->position], buf, size);
+ stream->position += size;
+ (*stream->buffer)[stream->position] = '\0';
+ return size;
+}
- public FILE *gc_memory_stream(char **buf, size_t *size) {
- gc_stream_t *stream = GC_MALLOC(sizeof(gc_stream_t));
- stream->size = size;
- stream->buffer = buf;
- *stream->size = 16;
- *stream->buffer = GC_MALLOC_ATOMIC(*stream->size);
- (*stream->buffer)[0] = '\0';
- stream->position = 0;
- return fwopen(stream, _gc_stream_write);
- }
+public
+FILE *gc_memory_stream(char **buf, size_t *size) {
+ gc_stream_t *stream = GC_MALLOC(sizeof(gc_stream_t));
+ stream->size = size;
+ stream->buffer = buf;
+ *stream->size = 16;
+ *stream->buffer = GC_MALLOC_ATOMIC(*stream->size);
+ (*stream->buffer)[0] = '\0';
+ stream->position = 0;
+ return fwopen(stream, _gc_stream_write);
+}
#else
-# error "This platform doesn't support fopencookie() or funopen()!"
+#error "This platform doesn't support fopencookie() or funopen()!"
#endif
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/stdlib/print.h b/src/stdlib/print.h
index 56953866..c7e59f8b 100644
--- a/src/stdlib/print.h
+++ b/src/stdlib/print.h
@@ -38,19 +38,19 @@ typedef struct {
bool uppercase;
int digits;
} hex_format_t;
-#define hex(x, ...) ((hex_format_t){.n=x, __VA_ARGS__})
+#define hex(x, ...) ((hex_format_t){.n = x, __VA_ARGS__})
typedef struct {
double d;
} hex_double_t;
-#define hex_double(x, ...) ((hex_double_t){.d=x, __VA_ARGS__})
+#define hex_double(x, ...) ((hex_double_t){.d = x, __VA_ARGS__})
typedef struct {
uint64_t n;
bool no_prefix;
int digits;
} oct_format_t;
-#define oct(x, ...) ((oct_format_t){.n=x, __VA_ARGS__})
+#define oct(x, ...) ((oct_format_t){.n = x, __VA_ARGS__})
typedef struct {
const char *str;
@@ -67,7 +67,7 @@ typedef struct {
char c;
int length;
} repeated_char_t;
-#define repeated_char(ch, len) ((repeated_char_t){.c=ch, .length=len})
+#define repeated_char(ch, len) ((repeated_char_t){.c = ch, .length = len})
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
#define FMT64 "ll"
@@ -87,7 +87,9 @@ PRINT_FN _print_bool(FILE *f, bool b) { return fputs(b ? "yes" : "no", f); }
PRINT_FN _print_str(FILE *f, const char *s) { return fputs(s ? s : "(null)", f); }
int _print_char(FILE *f, char c);
int _print_quoted(FILE *f, quoted_t quoted);
-PRINT_FN _print_string_slice(FILE *f, string_slice_t slice) { return slice.str ? fwrite(slice.str, 1, slice.length, f) : (size_t)fputs("(null)", f); }
+PRINT_FN _print_string_slice(FILE *f, string_slice_t slice) {
+ return slice.str ? fwrite(slice.str, 1, slice.length, f) : (size_t)fputs("(null)", f);
+}
PRINT_FN _print_repeated_char(FILE *f, repeated_char_t repeated) {
int len = 0;
for (int n = 0; n < repeated.length; n++)
@@ -99,31 +101,32 @@ extern int Text$print(FILE *stream, Text_t text);
extern int Path$print(FILE *stream, Path_t path);
extern int Int$print(FILE *f, Int_t i);
#ifndef _fprint1
-#define _fprint1(f, x) _Generic((x), \
- char*: _print_str, \
- const char*: _print_str, \
- char: _print_char, \
- bool: _print_bool, \
- int64_t: _print_int, \
- int32_t: _print_int, \
- int16_t: _print_int, \
- int8_t: _print_int, \
- uint64_t: _print_uint, \
- uint32_t: _print_uint, \
- uint16_t: _print_uint, \
- uint8_t: _print_uint, \
- float: _print_float, \
- double: _print_double, \
- hex_format_t: _print_hex, \
- hex_double_t: _print_hex_double, \
- oct_format_t: _print_oct, \
- quoted_t: _print_quoted, \
- string_slice_t: _print_string_slice, \
- repeated_char_t: _print_repeated_char, \
- Text_t: Text$print, \
- Path_t: Path$print, \
- Int_t: Int$print, \
- void*: _print_pointer)(f, x)
+#define _fprint1(f, x) \
+ _Generic((x), \
+ char *: _print_str, \
+ const char *: _print_str, \
+ char: _print_char, \
+ bool: _print_bool, \
+ int64_t: _print_int, \
+ int32_t: _print_int, \
+ int16_t: _print_int, \
+ int8_t: _print_int, \
+ uint64_t: _print_uint, \
+ uint32_t: _print_uint, \
+ uint16_t: _print_uint, \
+ uint8_t: _print_uint, \
+ float: _print_float, \
+ double: _print_double, \
+ hex_format_t: _print_hex, \
+ hex_double_t: _print_hex_double, \
+ oct_format_t: _print_oct, \
+ quoted_t: _print_quoted, \
+ string_slice_t: _print_string_slice, \
+ repeated_char_t: _print_repeated_char, \
+ Text_t: Text$print, \
+ Path_t: Path$print, \
+ Int_t: Int$print, \
+ void *: _print_pointer)(f, x)
#endif
typedef struct {
@@ -135,19 +138,31 @@ typedef struct {
FILE *gc_memory_stream(char **buf, size_t *size);
#define _print(x) _n += _fprint1(_printing, x)
-#define _fprint(f, ...) ({ FILE *_printing = f; int _n = 0; MAP_LIST(_print, __VA_ARGS__); _n; })
+#define _fprint(f, ...) \
+ ({ \
+ FILE *_printing = f; \
+ int _n = 0; \
+ MAP_LIST(_print, __VA_ARGS__); \
+ _n; \
+ })
#define fprint(f, ...) _fprint(f, __VA_ARGS__, "\n")
#define print(...) fprint(stdout, __VA_ARGS__)
#define fprint_inline(f, ...) _fprint(f, __VA_ARGS__)
#define print_inline(...) fprint_inline(stdout, __VA_ARGS__)
-#define String(...) ({ \
- char *_buf = NULL; \
- size_t _size = 0; \
- FILE *_stream = gc_memory_stream(&_buf, &_size); \
- assert(_stream); \
- _fprint(_stream, __VA_ARGS__); \
- fflush(_stream); \
- _buf; })
-#define print_err(...) ({ fprint(stderr, "\033[31;1m", __VA_ARGS__, "\033[m"); exit(EXIT_FAILURE); })
+#define String(...) \
+ ({ \
+ char *_buf = NULL; \
+ size_t _size = 0; \
+ FILE *_stream = gc_memory_stream(&_buf, &_size); \
+ assert(_stream); \
+ _fprint(_stream, __VA_ARGS__); \
+ fflush(_stream); \
+ _buf; \
+ })
+#define print_err(...) \
+ ({ \
+ fprint(stderr, "\033[31;1m", __VA_ARGS__, "\033[m"); \
+ exit(EXIT_FAILURE); \
+ })
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/stdlib/random.h b/src/stdlib/random.h
index 8509dbd7..1a6e89a5 100644
--- a/src/stdlib/random.h
+++ b/src/stdlib/random.h
@@ -1,5 +1,5 @@
-#include <stdint.h>
#include <assert.h>
+#include <stdint.h>
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
#include <stdlib.h>
@@ -10,9 +10,9 @@ static ssize_t getrandom(void *buf, size_t buflen, unsigned int flags) {
}
#elif defined(__linux__)
// Use getrandom()
-# include <sys/random.h>
+#include <sys/random.h>
#else
- #error "Unsupported platform for secure random number generation"
+#error "Unsupported platform for secure random number generation"
#endif
static int64_t random_range(int64_t low, int64_t high) {
diff --git a/src/stdlib/simpleparse.c b/src/stdlib/simpleparse.c
index 1ee64036..3929c32b 100644
--- a/src/stdlib/simpleparse.c
+++ b/src/stdlib/simpleparse.c
@@ -26,41 +26,42 @@ static bool _match_word(const char **str, const char *target) {
return false;
}
-public const char *simpleparse(const char *str, int n, parse_type_e types[n], void *destinations[n])
-{
+public
+const char *simpleparse(const char *str, int n, parse_type_e types[n], void *destinations[n]) {
for (int i = 0; i < n; i++) {
switch (types[i]) {
case PARSE_SOME_OF: {
- if (destinations[i]) str += strspn(str, (char*)destinations[i]);
+ if (destinations[i]) str += strspn(str, (char *)destinations[i]);
break;
}
case PARSE_LITERAL: {
- const char *target = (const char*)destinations[i];
+ const char *target = (const char *)destinations[i];
if (target) {
- if (strncmp(str, target, strlen(target)) != 0)
- return str;
+ if (strncmp(str, target, strlen(target)) != 0) return str;
str += strlen(target);
}
break;
}
case PARSE_STRING: {
size_t len;
- static const char matching_pair[256] = {[(int)'(']=')', [(int)'{']='}', [(int)'[']=']',
- [(int)'"']='"', [(int)'\'']='\'', [(int)'`']='`', [(int)'<']='>'};
- if (i > 0 && i + 1 < n && types[i-1] == PARSE_LITERAL && types[i+1] == PARSE_LITERAL
- && destinations[i-1] && destinations[i+1]
- && strlen((char*)destinations[i-1]) == 1 && strlen((char*)destinations[i+1]) == 1
- && *(char*)destinations[i+1] == matching_pair[(int)*(char*)destinations[i-1]]) {
+ static const char matching_pair[256] = {[(int)'('] = ')', [(int)'{'] = '}', [(int)'['] = ']',
+ [(int)'"'] = '"', [(int)'\''] = '\'', [(int)'`'] = '`',
+ [(int)'<'] = '>'};
+ if (i > 0 && i + 1 < n && types[i - 1] == PARSE_LITERAL && types[i + 1] == PARSE_LITERAL
+ && destinations[i - 1] && destinations[i + 1] && strlen((char *)destinations[i - 1]) == 1
+ && strlen((char *)destinations[i + 1]) == 1
+ && *(char *)destinations[i + 1] == matching_pair[(int)*(char *)destinations[i - 1]]) {
len = 0;
- char special_characters[4] = {'\\', *(char*)destinations[i-1], *(char*)destinations[i+1], 0};
- for (int depth = 1; depth > 0; ) {
+ char special_characters[4] = {'\\', *(char *)destinations[i - 1], *(char *)destinations[i + 1], 0};
+ for (int depth = 1; depth > 0;) {
len += strcspn(str + len, special_characters);
if (str[len] == '\0') {
return str;
} else if (str[len] == '\\'
- && (special_characters[1] == '"' || special_characters[1] == '\'' || special_characters[1] == '`')) {
- if (str[len+1] == '\0') return str;
- len += 2;
+ && (special_characters[1] == '"' || special_characters[1] == '\''
+ || special_characters[1] == '`')) {
+ if (str[len + 1] == '\0') return str;
+ len += 2;
} else if (str[len] == special_characters[2]) { // Check for closing quotes before opening quotes
depth -= 1;
if (depth > 0) len += 1;
@@ -70,8 +71,8 @@ public const char *simpleparse(const char *str, int n, parse_type_e types[n], vo
len += 1;
}
}
- } else if (i + 1 < n && types[i+1] == PARSE_LITERAL) {
- const char *terminator = (const char*)destinations[i+1];
+ } else if (i + 1 < n && types[i + 1] == PARSE_LITERAL) {
+ const char *terminator = (const char *)destinations[i + 1];
if (terminator) {
const char *end = strstr(str, terminator);
if (!end) return str;
@@ -79,16 +80,17 @@ public const char *simpleparse(const char *str, int n, parse_type_e types[n], vo
} else {
len = strlen(str);
}
- } else if (i + 1 < n && types[i+1] == PARSE_SOME_OF) {
- len = destinations[i+1] ? strcspn(str, (char*)destinations[i+1]) : strlen(str);;
+ } else if (i + 1 < n && types[i + 1] == PARSE_SOME_OF) {
+ len = destinations[i + 1] ? strcspn(str, (char *)destinations[i + 1]) : strlen(str);
+ ;
} else {
len = strlen(str);
}
if (destinations[i]) {
- char *matched = GC_MALLOC_ATOMIC(len+1);
+ char *matched = GC_MALLOC_ATOMIC(len + 1);
memcpy(matched, str, len);
matched[len] = '\0';
- *(const char**)destinations[i] = matched;
+ *(const char **)destinations[i] = matched;
}
str += len;
break;
@@ -97,7 +99,7 @@ public const char *simpleparse(const char *str, int n, parse_type_e types[n], vo
char *end = NULL;
double val = strtod(str, &end);
if (end == str) return str;
- if (destinations[i]) *(double*)destinations[i] = val;
+ if (destinations[i]) *(double *)destinations[i] = val;
str = end;
break;
}
@@ -105,15 +107,17 @@ public const char *simpleparse(const char *str, int n, parse_type_e types[n], vo
char *end = NULL;
long val = strtol(str, &end, 10);
if (end == str) return str;
- if (destinations[i]) *(long*)destinations[i] = val;
+ if (destinations[i]) *(long *)destinations[i] = val;
str = end;
break;
}
case PARSE_BOOL: {
- if (_match_word(&str, "true") || _match_word(&str, "yes") || _match_word(&str, "on") || _match_word(&str, "1")) {
- if (destinations[i]) *(bool*)destinations[i] = true;
- } else if (_match_word(&str, "false") || _match_word(&str, "no") || _match_word(&str, "off") || _match_word(&str, "0")) {
- if (destinations[i]) *(bool*)destinations[i] = false;
+ if (_match_word(&str, "true") || _match_word(&str, "yes") || _match_word(&str, "on")
+ || _match_word(&str, "1")) {
+ if (destinations[i]) *(bool *)destinations[i] = true;
+ } else if (_match_word(&str, "false") || _match_word(&str, "no") || _match_word(&str, "off")
+ || _match_word(&str, "0")) {
+ if (destinations[i]) *(bool *)destinations[i] = false;
} else {
return str;
}
diff --git a/src/stdlib/simpleparse.h b/src/stdlib/simpleparse.h
index da077e20..d35a8b3b 100644
--- a/src/stdlib/simpleparse.h
+++ b/src/stdlib/simpleparse.h
@@ -22,30 +22,42 @@
#include "mapmacro.h"
-typedef struct { char c; } some_char_t;
-#define PARSE_SOME_OF(chars) ((some_char_t*)chars)
+typedef struct {
+ char c;
+} some_char_t;
+#define PARSE_SOME_OF(chars) ((some_char_t *)chars)
#define PARSE_WHITESPACE PARSE_SOME_OF(" \t\r\n\v")
-typedef enum {PARSE_LITERAL, PARSE_LONG, PARSE_DOUBLE, PARSE_BOOL, PARSE_STRING, PARSE_SOME_OF} parse_type_e;
-
-typedef struct { parse_type_e type; void *dest; } parse_element_t;
-
-#define _parse_type(dest) _Generic((dest), \
- some_char_t*: PARSE_SOME_OF, \
- const char*: PARSE_LITERAL, \
- char*: PARSE_LITERAL, \
- const char**: PARSE_STRING, \
- char**: PARSE_STRING, \
- double*: PARSE_DOUBLE, \
- long*: PARSE_LONG, \
- bool*: PARSE_BOOL)
-
-#define as_void_star(x) ((void*)x)
-#define strparse(str, ...) simpleparse(str, sizeof((const void*[]){__VA_ARGS__})/sizeof(void*), (parse_type_e[]){MAP_LIST(_parse_type, __VA_ARGS__)}, (void*[]){MAP_LIST(as_void_star, __VA_ARGS__)})
-#define fparse(file, ...) ({ char *_file_contents = NULL; size_t _capacity; \
- ssize_t _just_read = getdelim(&_file_contents, &_capacity, '\0', file); \
- const char *_parse_err = _just_read > 0 ? strparse(_file_contents, __VA_ARGS__) : "No such file"; \
- if (_file_contents) free(_file_contents); \
- _parse_err; })
+typedef enum { PARSE_LITERAL, PARSE_LONG, PARSE_DOUBLE, PARSE_BOOL, PARSE_STRING, PARSE_SOME_OF } parse_type_e;
+
+typedef struct {
+ parse_type_e type;
+ void *dest;
+} parse_element_t;
+
+#define _parse_type(dest) \
+ _Generic((dest), \
+ some_char_t *: PARSE_SOME_OF, \
+ const char *: PARSE_LITERAL, \
+ char *: PARSE_LITERAL, \
+ const char **: PARSE_STRING, \
+ char **: PARSE_STRING, \
+ double *: PARSE_DOUBLE, \
+ long *: PARSE_LONG, \
+ bool *: PARSE_BOOL)
+
+#define as_void_star(x) ((void *)x)
+#define strparse(str, ...) \
+ simpleparse(str, sizeof((const void *[]){__VA_ARGS__}) / sizeof(void *), \
+ (parse_type_e[]){MAP_LIST(_parse_type, __VA_ARGS__)}, (void *[]){MAP_LIST(as_void_star, __VA_ARGS__)})
+#define fparse(file, ...) \
+ ({ \
+ char *_file_contents = NULL; \
+ size_t _capacity; \
+ ssize_t _just_read = getdelim(&_file_contents, &_capacity, '\0', file); \
+ const char *_parse_err = _just_read > 0 ? strparse(_file_contents, __VA_ARGS__) : "No such file"; \
+ if (_file_contents) free(_file_contents); \
+ _parse_err; \
+ })
const char *simpleparse(const char *str, int n, parse_type_e types[n], void *destinations[n]);
diff --git a/src/stdlib/siphash-internals.h b/src/stdlib/siphash-internals.h
index b359cea7..c8ec1142 100644
--- a/src/stdlib/siphash-internals.h
+++ b/src/stdlib/siphash-internals.h
@@ -51,24 +51,25 @@ struct siphash {
uint64_t v1;
uint64_t v2;
uint64_t v3;
- uint64_t b;
+ uint64_t b;
};
typedef struct siphash siphash;
-#define ROTATE(x, b) (uint64_t)( ((x) << (b)) | ( (x) >> (64 - (b))) )
+#define ROTATE(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
-#define HALF_ROUND(a,b,c,d,s,t) \
- a += b; c += d; \
- b = ROTATE(b, s) ^ a; \
- d = ROTATE(d, t) ^ c; \
+#define HALF_ROUND(a, b, c, d, s, t) \
+ a += b; \
+ c += d; \
+ b = ROTATE(b, s) ^ a; \
+ d = ROTATE(d, t) ^ c; \
a = ROTATE(a, 32);
-#define DOUBLE_ROUND(v0,v1,v2,v3) \
- HALF_ROUND(v0,v1,v2,v3,13,16); \
- HALF_ROUND(v2,v1,v0,v3,17,21); \
- HALF_ROUND(v0,v1,v2,v3,13,16); \
- HALF_ROUND(v2,v1,v0,v3,17,21);
+#define DOUBLE_ROUND(v0, v1, v2, v3) \
+ HALF_ROUND(v0, v1, v2, v3, 13, 16); \
+ HALF_ROUND(v2, v1, v0, v3, 17, 21); \
+ HALF_ROUND(v0, v1, v2, v3, 13, 16); \
+ HALF_ROUND(v2, v1, v0, v3, 17, 21);
-MACROLIKE void siphashinit (siphash *sh, size_t src_sz) {
+MACROLIKE void siphashinit(siphash *sh, size_t src_sz) {
const uint64_t k0 = TOMO_HASH_KEY[0];
const uint64_t k1 = TOMO_HASH_KEY[1];
sh->b = (uint64_t)src_sz << 56;
@@ -77,20 +78,20 @@ MACROLIKE void siphashinit (siphash *sh, size_t src_sz) {
sh->v2 = k0 ^ 0x6c7967656e657261ULL;
sh->v3 = k1 ^ 0x7465646279746573ULL;
}
-MACROLIKE void siphashadd64bits (siphash *sh, const uint64_t in) {
+MACROLIKE void siphashadd64bits(siphash *sh, const uint64_t in) {
const uint64_t mi = in;
sh->v3 ^= mi;
- DOUBLE_ROUND(sh->v0,sh->v1,sh->v2,sh->v3);
+ DOUBLE_ROUND(sh->v0, sh->v1, sh->v2, sh->v3);
sh->v0 ^= mi;
}
-MACROLIKE uint64_t siphashfinish_last_part (siphash *sh, uint64_t t) {
+MACROLIKE uint64_t siphashfinish_last_part(siphash *sh, uint64_t t) {
sh->b |= t;
sh->v3 ^= sh->b;
- DOUBLE_ROUND(sh->v0,sh->v1,sh->v2,sh->v3);
+ DOUBLE_ROUND(sh->v0, sh->v1, sh->v2, sh->v3);
sh->v0 ^= sh->b;
sh->v2 ^= 0xff;
- DOUBLE_ROUND(sh->v0,sh->v1,sh->v2,sh->v3);
- DOUBLE_ROUND(sh->v0,sh->v1,sh->v2,sh->v3);
+ DOUBLE_ROUND(sh->v0, sh->v1, sh->v2, sh->v3);
+ DOUBLE_ROUND(sh->v0, sh->v1, sh->v2, sh->v3);
return (sh->v0 ^ sh->v1) ^ (sh->v2 ^ sh->v3);
}
/* This union helps us avoid doing weird things with pointers that can cause old
@@ -99,26 +100,26 @@ MACROLIKE uint64_t siphashfinish_last_part (siphash *sh, uint64_t t) {
union SipHash64_union {
uint64_t u64;
uint32_t u32;
- uint8_t u8[8];
+ uint8_t u8[8];
};
-MACROLIKE uint64_t siphashfinish (siphash *sh, const uint8_t *src, size_t src_sz) {
- union SipHash64_union t = { 0 };
+MACROLIKE uint64_t siphashfinish(siphash *sh, const uint8_t *src, size_t src_sz) {
+ union SipHash64_union t = {0};
switch (src_sz) {
- /* Falls through */
- case 7: t.u8[6] = src[6];
- /* Falls through */
- case 6: t.u8[5] = src[5];
- /* Falls through */
- case 5: t.u8[4] = src[4];
- /* Falls through */
- case 4: t.u8[3] = src[3];
- /* Falls through */
- case 3: t.u8[2] = src[2];
- /* Falls through */
- case 2: t.u8[1] = src[1];
- /* Falls through */
- case 1: t.u8[0] = src[0];
- default: break;
+ /* Falls through */
+ case 7: t.u8[6] = src[6];
+ /* Falls through */
+ case 6: t.u8[5] = src[5];
+ /* Falls through */
+ case 5: t.u8[4] = src[4];
+ /* Falls through */
+ case 4: t.u8[3] = src[3];
+ /* Falls through */
+ case 3: t.u8[2] = src[2];
+ /* Falls through */
+ case 2: t.u8[1] = src[1];
+ /* Falls through */
+ case 1: t.u8[0] = src[0];
+ default: break;
}
return siphashfinish_last_part(sh, t.u64);
}
diff --git a/src/stdlib/siphash.c b/src/stdlib/siphash.c
index 274b3195..9af845e7 100644
--- a/src/stdlib/siphash.c
+++ b/src/stdlib/siphash.c
@@ -5,7 +5,8 @@
#include "siphash.h"
#include "util.h"
-public uint64_t TOMO_HASH_KEY[2] = {23, 42}; // Randomized in tomo_init()
+public
+uint64_t TOMO_HASH_KEY[2] = {23, 42}; // Randomized in tomo_init()
/* <MIT License>
Copyright (c) 2013 Marek Majkowski <marek@popcount.org>
@@ -53,10 +54,10 @@ PUREFUNC public uint64_t siphash24(const uint8_t *src, size_t src_sz) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-align"
#endif
- const uint64_t *in = (uint64_t*)src;
+ const uint64_t *in = (uint64_t *)src;
/* Find largest src_sz evenly divisible by 8 bytes. */
const ptrdiff_t src_sz_nearest_8bits = ((ptrdiff_t)src_sz >> 3) << 3;
- const uint64_t *goal = (uint64_t*)(src + src_sz_nearest_8bits);
+ const uint64_t *goal = (uint64_t *)(src + src_sz_nearest_8bits);
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
@@ -74,7 +75,8 @@ PUREFUNC public uint64_t siphash24(const uint8_t *src, size_t src_sz) {
uint64_t in_64;
memcpy(&in_64, in, sizeof(uint64_t));
siphashadd64bits(&sh, in_64);
- in += 8; src_sz -= 8;
+ in += 8;
+ src_sz -= 8;
}
return siphashfinish(&sh, (uint8_t *)in, src_sz);
}
diff --git a/src/stdlib/siphash.h b/src/stdlib/siphash.h
index 67bad582..3dbef0fd 100644
--- a/src/stdlib/siphash.h
+++ b/src/stdlib/siphash.h
@@ -2,8 +2,8 @@
// An implementation of the SipHash algorithm.
-#include <stdint.h>
#include <stddef.h>
+#include <stdint.h>
#include "util.h"
diff --git a/src/stdlib/stacktrace.c b/src/stdlib/stacktrace.c
index f408d753..9f01a4bf 100644
--- a/src/stdlib/stacktrace.c
+++ b/src/stdlib/stacktrace.c
@@ -1,6 +1,6 @@
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
-#endif
+#endif
#include <dlfcn.h>
#include <err.h>
@@ -19,8 +19,7 @@
extern bool USE_COLOR;
-static void fprint_context(FILE *out, const char *filename, int lineno, int context_before, int context_after)
-{
+static void fprint_context(FILE *out, const char *filename, int lineno, int context_before, int context_after) {
FILE *f = fopen(filename, "r");
if (!f) return;
char *line = NULL;
@@ -33,35 +32,31 @@ static void fprint_context(FILE *out, const char *filename, int lineno, int cont
num_width += 1;
while ((nread = getline(&line, &size, f)) != -1) {
- if (line[strlen(line)-1] == '\n')
- line[strlen(line)-1] = '\0';
+ if (line[strlen(line) - 1] == '\n') line[strlen(line) - 1] = '\0';
if (cur_line >= lineno - context_before) {
int w = 1;
- for (int n = cur_line; n >= 10; n /= 10) w += 1;
+ for (int n = cur_line; n >= 10; n /= 10)
+ w += 1;
if (USE_COLOR) {
fprint(out, cur_line == lineno ? "\033[31;1m>\033[m " : " ", "\033[2m",
- repeated_char(' ', num_width-w),
- cur_line, "\033(0\x78\033(B", cur_line == lineno ? "\033[0;31;1m" : "\033[0m",
- line, "\033[m");
+ repeated_char(' ', num_width - w), cur_line, "\033(0\x78\033(B",
+ cur_line == lineno ? "\033[0;31;1m" : "\033[0m", line, "\033[m");
} else {
- fprint(out, cur_line == lineno ? "> " : " ",
- repeated_char(' ', num_width-w),
- cur_line, "| ", line);
+ fprint(out, cur_line == lineno ? "> " : " ", repeated_char(' ', num_width - w), cur_line, "| ", line);
}
}
cur_line += 1;
- if (cur_line > lineno + context_after)
- break;
+ if (cur_line > lineno + context_after) break;
}
if (line) free(line);
fclose(f);
}
-static void _print_stack_frame(FILE *out, const char *cwd, const char *install_dir, const char *function, const char *filename, int lineno)
-{
+static void _print_stack_frame(FILE *out, const char *cwd, const char *install_dir, const char *function,
+ const char *filename, int lineno) {
if (function == NULL) {
fprint(out, USE_COLOR ? "\033[2m...unknown function...\033[m" : "...unknown function...");
return;
@@ -71,7 +66,7 @@ static void _print_stack_frame(FILE *out, const char *cwd, const char *install_d
if (function[0] == '\0') function = "???";
char *function_display = GC_MALLOC_ATOMIC(strlen(function));
- memcpy(function_display, function, strlen(function)+1);
+ memcpy(function_display, function, strlen(function) + 1);
char *last_dollar = strrchr(function_display, '$');
if (last_dollar) *last_dollar = '\0';
for (char *p = function_display; *p; p++) {
@@ -79,14 +74,12 @@ static void _print_stack_frame(FILE *out, const char *cwd, const char *install_d
}
if (filename) {
- if (strncmp(filename, cwd, strlen(cwd)) == 0)
- filename += strlen(cwd);
+ if (strncmp(filename, cwd, strlen(cwd)) == 0) filename += strlen(cwd);
fprint_inline(out, USE_COLOR ? "\033[1mIn \033[33m" : "In ", function_display, USE_COLOR ? "()\033[37m" : "()");
if (install_dir[0] && strncmp(filename, install_dir, strlen(install_dir)) == 0)
fprint_inline(out, USE_COLOR ? " in library \033[35m" : " in library ", filename, ":", lineno);
- else
- fprint(out, USE_COLOR ? " in \033[35m" : " in ", filename, ":", lineno);
+ else fprint(out, USE_COLOR ? " in \033[35m" : " in ", filename, ":", lineno);
fprint(out, USE_COLOR ? "\033[m" : "");
fprint_context(out, filename, lineno, 3, 1);
} else {
@@ -94,48 +87,41 @@ static void _print_stack_frame(FILE *out, const char *cwd, const char *install_d
}
}
-__attribute__ ((noinline))
-public void print_stacktrace(FILE *out, int offset)
-{
+__attribute__((noinline)) public
+void print_stacktrace(FILE *out, int offset) {
char cwd[PATH_MAX];
- if (getcwd(cwd, sizeof(cwd)) == NULL)
- errx(1, "Path too large!");
+ if (getcwd(cwd, sizeof(cwd)) == NULL) errx(1, "Path too large!");
size_t cwd_len = strlen(cwd);
- if (cwd_len + 2 > sizeof(cwd))
- errx(1, "Path too large!");
+ if (cwd_len + 2 > sizeof(cwd)) errx(1, "Path too large!");
cwd[cwd_len++] = '/';
cwd[cwd_len] = '\0';
- const char *install_dir = TOMO_PREFIX"/share/tomo_"TOMO_VERSION"/installed/";
+ const char *install_dir = TOMO_PREFIX "/share/tomo_" TOMO_VERSION "/installed/";
static void *stack[1024];
- int64_t size = (int64_t)backtrace(stack, sizeof(stack)/sizeof(stack[0]));
+ int64_t size = (int64_t)backtrace(stack, sizeof(stack) / sizeof(stack[0]));
char **strings = backtrace_symbols(stack, size);
bool main_func_onwards = false;
- for (int64_t i = size-1; i > offset; i--) {
+ for (int64_t i = size - 1; i > offset; i--) {
Dl_info info;
- void *call_address = stack[i]-1;
+ void *call_address = stack[i] - 1;
if (dladdr(call_address, &info) && info.dli_fname) {
const char *file = info.dli_fname;
uintptr_t frame_offset = (uintptr_t)call_address - (uintptr_t)info.dli_fbase;
- FILE *fp = popen(String("addr2line -f -e '", file, "' ", (void*)frame_offset, " 2>/dev/null"), "r");
+ FILE *fp = popen(String("addr2line -f -e '", file, "' ", (void *)frame_offset, " 2>/dev/null"), "r");
if (fp) {
const char *function = NULL, *filename = NULL;
long line_num = 0;
if (fparse(fp, &function, "\n", &filename, ":", &line_num) == NULL) {
- if (starts_with(function, "main$"))
- main_func_onwards = true;
- if (main_func_onwards)
- _print_stack_frame(out, cwd, install_dir, function, filename, line_num);
+ if (starts_with(function, "main$")) main_func_onwards = true;
+ if (main_func_onwards) _print_stack_frame(out, cwd, install_dir, function, filename, line_num);
} else {
- if (main_func_onwards)
- _print_stack_frame(out, cwd, install_dir, NULL, NULL, line_num);
+ if (main_func_onwards) _print_stack_frame(out, cwd, install_dir, NULL, NULL, line_num);
}
pclose(fp);
}
} else {
- if (main_func_onwards)
- _print_stack_frame(out, cwd, install_dir, NULL, NULL, 0);
+ if (main_func_onwards) _print_stack_frame(out, cwd, install_dir, NULL, NULL, 0);
}
if (main_func_onwards && i - 1 > offset) fputs("\n", out);
}
diff --git a/src/stdlib/stacktrace.h b/src/stdlib/stacktrace.h
index 828bbe98..36e81bea 100644
--- a/src/stdlib/stacktrace.h
+++ b/src/stdlib/stacktrace.h
@@ -1,5 +1,4 @@
#pragma once
#include <stdio.h>
-__attribute__ ((noinline))
-void print_stacktrace(FILE *out, int offset);
+__attribute__((noinline)) void print_stacktrace(FILE *out, int offset);
diff --git a/src/stdlib/stdlib.c b/src/stdlib/stdlib.c
index 159acdb3..411ce300 100644
--- a/src/stdlib/stdlib.c
+++ b/src/stdlib/stdlib.c
@@ -37,16 +37,17 @@ static ssize_t getrandom(void *buf, size_t buflen, unsigned int flags) {
}
#elif defined(__linux__)
// Use getrandom()
-# include <sys/random.h>
+#include <sys/random.h>
#else
- #error "Unsupported platform for secure random number generation"
+#error "Unsupported platform for secure random number generation"
#endif
-public bool USE_COLOR;
-public Text_t TOMO_VERSION_TEXT = Text(TOMO_VERSION);
+public
+bool USE_COLOR;
+public
+Text_t TOMO_VERSION_TEXT = Text(TOMO_VERSION);
-static _Noreturn void signal_handler(int sig, siginfo_t *info, void *userdata)
-{
+static _Noreturn void signal_handler(int sig, siginfo_t *info, void *userdata) {
(void)info, (void)userdata;
assert(sig == SIGILL);
fflush(stdout);
@@ -58,107 +59,92 @@ static _Noreturn void signal_handler(int sig, siginfo_t *info, void *userdata)
_exit(1);
}
-public void tomo_init(void)
-{
- GC_INIT();
- USE_COLOR = getenv("COLOR") ? strcmp(getenv("COLOR"), "1") == 0 : isatty(STDOUT_FILENO);
- if (getenv("NO_COLOR") && getenv("NO_COLOR")[0] != '\0')
- USE_COLOR = false;
-
- setlocale(LC_ALL, "");
- assert(getrandom(TOMO_HASH_KEY, sizeof(TOMO_HASH_KEY), 0) == sizeof(TOMO_HASH_KEY));
-
- struct sigaction sigact;
- sigact.sa_sigaction = signal_handler;
- sigemptyset(&sigact.sa_mask);
- sigact.sa_flags = 0;
- sigaction(SIGILL, &sigact, (struct sigaction *)NULL);
+public
+void tomo_init(void) {
+ GC_INIT();
+ USE_COLOR = getenv("COLOR") ? strcmp(getenv("COLOR"), "1") == 0 : isatty(STDOUT_FILENO);
+ if (getenv("NO_COLOR") && getenv("NO_COLOR")[0] != '\0') USE_COLOR = false;
+
+ setlocale(LC_ALL, "");
+ assert(getrandom(TOMO_HASH_KEY, sizeof(TOMO_HASH_KEY), 0) == sizeof(TOMO_HASH_KEY));
+
+ struct sigaction sigact;
+ sigact.sa_sigaction = signal_handler;
+ sigemptyset(&sigact.sa_mask);
+ sigact.sa_flags = 0;
+ sigaction(SIGILL, &sigact, (struct sigaction *)NULL);
}
-static bool parse_single_arg(const TypeInfo_t *info, char *arg, void *dest)
-{
+static bool parse_single_arg(const TypeInfo_t *info, char *arg, void *dest) {
if (!arg) return false;
- if (info->tag == OptionalInfo && streq(arg, "none"))
- return true;
+ if (info->tag == OptionalInfo && streq(arg, "none")) return true;
while (info->tag == OptionalInfo)
info = info->OptionalInfo.type;
if (info == &Int$info) {
OptionalInt_t parsed = Int$from_str(arg);
- if (parsed.small != 0)
- *(OptionalInt_t*)dest = parsed;
+ if (parsed.small != 0) *(OptionalInt_t *)dest = parsed;
return parsed.small != 0;
} else if (info == &Int64$info) {
OptionalInt64_t parsed = Int64$parse(Text$from_str(arg), NULL);
- if (!parsed.is_none)
- *(OptionalInt64_t*)dest = parsed;
+ if (!parsed.is_none) *(OptionalInt64_t *)dest = parsed;
return !parsed.is_none;
} else if (info == &Int32$info) {
OptionalInt32_t parsed = Int32$parse(Text$from_str(arg), NULL);
- if (!parsed.is_none)
- *(OptionalInt32_t*)dest = parsed;
+ if (!parsed.is_none) *(OptionalInt32_t *)dest = parsed;
return !parsed.is_none;
} else if (info == &Int16$info) {
OptionalInt16_t parsed = Int16$parse(Text$from_str(arg), NULL);
- if (!parsed.is_none)
- *(OptionalInt16_t*)dest = parsed;
+ if (!parsed.is_none) *(OptionalInt16_t *)dest = parsed;
return !parsed.is_none;
} else if (info == &Int8$info) {
OptionalInt8_t parsed = Int8$parse(Text$from_str(arg), NULL);
- if (!parsed.is_none)
- *(OptionalInt8_t*)dest = parsed;
+ if (!parsed.is_none) *(OptionalInt8_t *)dest = parsed;
return !parsed.is_none;
} else if (info == &Bool$info) {
OptionalBool_t parsed = Bool$parse(Text$from_str(arg), NULL);
- if (parsed != NONE_BOOL)
- *(OptionalBool_t*)dest = parsed;
+ if (parsed != NONE_BOOL) *(OptionalBool_t *)dest = parsed;
return parsed != NONE_BOOL;
} else if (info == &Num$info) {
OptionalNum_t parsed = Num$parse(Text$from_str(arg), NULL);
- if (!isnan(parsed))
- *(OptionalNum_t*)dest = parsed;
+ if (!isnan(parsed)) *(OptionalNum_t *)dest = parsed;
return !isnan(parsed);
} else if (info == &Num32$info) {
OptionalNum32_t parsed = Num32$parse(Text$from_str(arg), NULL);
- if (!isnan(parsed))
- *(OptionalNum32_t*)dest = parsed;
+ if (!isnan(parsed)) *(OptionalNum32_t *)dest = parsed;
return !isnan(parsed);
} else if (info == &Path$info) {
- *(OptionalPath_t*)dest = Path$from_str(arg);
+ *(OptionalPath_t *)dest = Path$from_str(arg);
return true;
} else if (info->tag == TextInfo) {
- *(OptionalText_t*)dest = Text$from_str(arg);
+ *(OptionalText_t *)dest = Text$from_str(arg);
return true;
} else if (info->tag == EnumInfo) {
for (int t = 0; t < info->EnumInfo.num_tags; t++) {
NamedType_t named = info->EnumInfo.tags[t];
size_t len = strlen(named.name);
if (strncmp(arg, named.name, len) == 0 && (arg[len] == '\0' || arg[len] == ':')) {
- *(int32_t*)dest = (t + 1);
+ *(int32_t *)dest = (t + 1);
// Simple tag (no associated data):
if (!named.type || (named.type->tag == StructInfo && named.type->StructInfo.num_fields == 0))
return true;
// Single-argument tag:
- if (arg[len] != ':')
- print_err("Invalid value for ", t, ".", named.name, ": ", arg);
+ if (arg[len] != ':') print_err("Invalid value for ", t, ".", named.name, ": ", arg);
size_t offset = sizeof(int32_t);
if (named.type->align > 0 && offset % (size_t)named.type->align > 0)
offset += (size_t)named.type->align - (offset % (size_t)named.type->align);
- if (!parse_single_arg(named.type, arg + len + 1, dest + offset))
- return false;
+ if (!parse_single_arg(named.type, arg + len + 1, dest + offset)) return false;
return true;
}
}
print_err("Invalid value for ", info->EnumInfo.name, ": ", arg);
} else if (info->tag == StructInfo) {
- if (info->StructInfo.num_fields == 0)
- return true;
- else if (info->StructInfo.num_fields == 1)
- return parse_single_arg(info->StructInfo.fields[0].type, arg, dest);
+ if (info->StructInfo.num_fields == 0) return true;
+ else if (info->StructInfo.num_fields == 1) return parse_single_arg(info->StructInfo.fields[0].type, arg, dest);
Text_t t = generic_as_text(NULL, false, info);
print_err("Unsupported multi-argument struct type for argument parsing: ", t);
@@ -173,41 +159,36 @@ static bool parse_single_arg(const TypeInfo_t *info, char *arg, void *dest)
return false;
}
-static List_t parse_list(const TypeInfo_t *item_info, int n, char *args[])
-{
+static List_t parse_list(const TypeInfo_t *item_info, int n, char *args[]) {
int64_t padded_size = item_info->size;
if ((padded_size % item_info->align) > 0)
padded_size = padded_size + item_info->align - (padded_size % item_info->align);
List_t items = {
- .stride=padded_size,
- .length=n,
- .data=GC_MALLOC((size_t)(padded_size*n)),
+ .stride = padded_size,
+ .length = n,
+ .data = GC_MALLOC((size_t)(padded_size * n)),
};
for (int i = 0; i < n; i++) {
- bool success = parse_single_arg(item_info, args[i], items.data + items.stride*i);
- if (!success)
- print_err("Couldn't parse argument: ", args[i]);
+ bool success = parse_single_arg(item_info, args[i], items.data + items.stride * i);
+ if (!success) print_err("Couldn't parse argument: ", args[i]);
}
return items;
}
// Arguments take the form key=value, with a guarantee that there is an '='
-static Table_t parse_table(const TypeInfo_t *table, int n, char *args[])
-{
+static Table_t parse_table(const TypeInfo_t *table, int n, char *args[]) {
const TypeInfo_t *key = table->TableInfo.key, *value = table->TableInfo.value;
int64_t padded_size = key->size;
- if ((padded_size % value->align) > 0)
- padded_size = padded_size + value->align - (padded_size % value->align);
+ if ((padded_size % value->align) > 0) padded_size = padded_size + value->align - (padded_size % value->align);
int64_t value_offset = padded_size;
padded_size += value->size;
- if ((padded_size % key->align) > 0)
- padded_size = padded_size + key->align - (padded_size % key->align);
+ if ((padded_size % key->align) > 0) padded_size = padded_size + key->align - (padded_size % key->align);
List_t entries = {
- .stride=padded_size,
- .length=n,
- .data=GC_MALLOC((size_t)(padded_size*n)),
+ .stride = padded_size,
+ .length = n,
+ .data = GC_MALLOC((size_t)(padded_size * n)),
};
for (int i = 0; i < n; i++) {
char *key_arg = args[i];
@@ -216,13 +197,11 @@ static Table_t parse_table(const TypeInfo_t *table, int n, char *args[])
char *value_arg = equals + 1;
*equals = '\0';
- bool success = parse_single_arg(key, key_arg, entries.data + entries.stride*i);
- if (!success)
- print_err("Couldn't parse table key: ", key_arg);
+ bool success = parse_single_arg(key, key_arg, entries.data + entries.stride * i);
+ if (!success) print_err("Couldn't parse table key: ", key_arg);
- success = parse_single_arg(value, value_arg, entries.data + entries.stride*i + value_offset);
- if (!success)
- print_err("Couldn't parse table value: ", value_arg);
+ success = parse_single_arg(value, value_arg, entries.data + entries.stride * i + value_offset);
+ if (!success) print_err("Couldn't parse table value: ", value_arg);
*equals = '=';
}
@@ -233,13 +212,14 @@ static Table_t parse_table(const TypeInfo_t *table, int n, char *args[])
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstack-protector"
#endif
-public void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help, const char *version, int spec_len, cli_arg_t spec[spec_len])
-{
+public
+void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help, const char *version, int spec_len,
+ cli_arg_t spec[spec_len]) {
bool populated_args[spec_len];
bool used_args[argc];
memset(populated_args, 0, sizeof(populated_args));
memset(used_args, 0, sizeof(used_args));
- for (int i = 1; i < argc; ) {
+ for (int i = 1; i < argc;) {
if (argv[i][0] == '-' && argv[i][1] == '-') {
if (argv[i][2] == '\0') { // "--" signals the rest of the arguments are literal
used_args[i] = true;
@@ -252,58 +232,54 @@ public void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help,
while (non_opt_type->tag == OptionalInfo)
non_opt_type = non_opt_type->OptionalInfo.type;
- if (non_opt_type == &Bool$info
- && strncmp(argv[i], "--no-", strlen("--no-")) == 0
+ if (non_opt_type == &Bool$info && strncmp(argv[i], "--no-", strlen("--no-")) == 0
&& strcmp(argv[i] + strlen("--no-"), spec[s].name) == 0) {
- *(OptionalBool_t*)spec[s].dest = false;
+ *(OptionalBool_t *)spec[s].dest = false;
populated_args[s] = true;
used_args[i] = true;
goto next_arg;
}
- if (strncmp(spec[s].name, argv[i] + 2, strlen(spec[s].name)) != 0)
- continue;
+ if (strncmp(spec[s].name, argv[i] + 2, strlen(spec[s].name)) != 0) continue;
- char after_name = argv[i][2+strlen(spec[s].name)];
+ char after_name = argv[i][2 + strlen(spec[s].name)];
if (after_name == '\0') { // --foo val
used_args[i] = true;
if (non_opt_type->tag == ListInfo) {
int num_args = 0;
while (i + 1 + num_args < argc) {
- if (argv[i+1+num_args][0] == '-')
- break;
- used_args[i+1+num_args] = true;
+ if (argv[i + 1 + num_args][0] == '-') break;
+ used_args[i + 1 + num_args] = true;
num_args += 1;
}
populated_args[s] = true;
- *(OptionalList_t*)spec[s].dest = parse_list(non_opt_type->ListInfo.item, num_args, &argv[i+1]);
+ *(OptionalList_t *)spec[s].dest =
+ parse_list(non_opt_type->ListInfo.item, num_args, &argv[i + 1]);
} else if (non_opt_type->tag == TableInfo) {
int num_args = 0;
while (i + 1 + num_args < argc) {
- if (argv[i+1+num_args][0] == '-' || !strchr(argv[i+1+num_args], '='))
- break;
- used_args[i+1+num_args] = true;
+ if (argv[i + 1 + num_args][0] == '-' || !strchr(argv[i + 1 + num_args], '=')) break;
+ used_args[i + 1 + num_args] = true;
num_args += 1;
}
populated_args[s] = true;
- *(OptionalTable_t*)spec[s].dest = parse_table(non_opt_type, num_args, &argv[i+1]);
+ *(OptionalTable_t *)spec[s].dest = parse_table(non_opt_type, num_args, &argv[i + 1]);
} else if (non_opt_type == &Bool$info) { // --flag
populated_args[s] = true;
- *(OptionalBool_t*)spec[s].dest = true;
+ *(OptionalBool_t *)spec[s].dest = true;
} else {
- if (i + 1 >= argc)
- print_err("Missing argument: ", argv[i], "\n", usage);
- used_args[i+1] = true;
- populated_args[s] = parse_single_arg(spec[s].type, argv[i+1], spec[s].dest);
+ if (i + 1 >= argc) print_err("Missing argument: ", argv[i], "\n", usage);
+ used_args[i + 1] = true;
+ populated_args[s] = parse_single_arg(spec[s].type, argv[i + 1], spec[s].dest);
if (!populated_args[s])
- print_err("Couldn't parse argument: ", argv[i], " ", argv[i+1], "\n", usage);
+ print_err("Couldn't parse argument: ", argv[i], " ", argv[i + 1], "\n", usage);
}
goto next_arg;
} else if (after_name == '=') { // --foo=val
used_args[i] = true;
- populated_args[s] = parse_single_arg(spec[s].type, 2 + argv[i] + strlen(spec[s].name) + 1, spec[s].dest);
- if (!populated_args[s])
- print_err("Couldn't parse argument: ", argv[i], "\n", usage);
+ populated_args[s] =
+ parse_single_arg(spec[s].type, 2 + argv[i] + strlen(spec[s].name) + 1, spec[s].dest);
+ if (!populated_args[s]) print_err("Couldn't parse argument: ", argv[i], "\n", usage);
goto next_arg;
} else {
continue;
@@ -324,8 +300,7 @@ public void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help,
for (char *f = argv[i] + 1; *f; f++) {
char flag[] = {'-', *f, 0};
for (int s = 0; s < spec_len; s++) {
- if (spec[s].name[0] != *f || strlen(spec[s].name) > 1)
- continue;
+ if (spec[s].name[0] != *f || strlen(spec[s].name) > 1) continue;
const TypeInfo_t *non_opt_type = spec[s].type;
while (non_opt_type->tag == OptionalInfo)
@@ -335,32 +310,31 @@ public void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help,
if (f[1]) print_err("No value provided for ", flag, "\n", usage);
int num_args = 0;
while (i + 1 + num_args < argc) {
- if (argv[i+1+num_args][0] == '-')
- break;
- used_args[i+1+num_args] = true;
+ if (argv[i + 1 + num_args][0] == '-') break;
+ used_args[i + 1 + num_args] = true;
num_args += 1;
}
populated_args[s] = true;
- *(OptionalList_t*)spec[s].dest = parse_list(non_opt_type->ListInfo.item, num_args, &argv[i+1]);
+ *(OptionalList_t *)spec[s].dest =
+ parse_list(non_opt_type->ListInfo.item, num_args, &argv[i + 1]);
} else if (non_opt_type->tag == TableInfo) {
int num_args = 0;
while (i + 1 + num_args < argc) {
- if (argv[i+1+num_args][0] == '-' || !strchr(argv[i+1+num_args], '='))
- break;
- used_args[i+1+num_args] = true;
+ if (argv[i + 1 + num_args][0] == '-' || !strchr(argv[i + 1 + num_args], '=')) break;
+ used_args[i + 1 + num_args] = true;
num_args += 1;
}
populated_args[s] = true;
- *(OptionalTable_t*)spec[s].dest = parse_table(non_opt_type, num_args, &argv[i+1]);
+ *(OptionalTable_t *)spec[s].dest = parse_table(non_opt_type, num_args, &argv[i + 1]);
} else if (non_opt_type == &Bool$info) { // -f
populated_args[s] = true;
- *(OptionalBool_t*)spec[s].dest = true;
+ *(OptionalBool_t *)spec[s].dest = true;
} else {
- if (f[1] || i+1 >= argc) print_err("No value provided for ", flag, "\n", usage);
- used_args[i+1] = true;
- populated_args[s] = parse_single_arg(spec[s].type, argv[i+1], spec[s].dest);
+ if (f[1] || i + 1 >= argc) print_err("No value provided for ", flag, "\n", usage);
+ used_args[i + 1] = true;
+ populated_args[s] = parse_single_arg(spec[s].type, argv[i + 1], spec[s].dest);
if (!populated_args[s])
- print_err("Couldn't parse argument: ", argv[i], " ", argv[i+1], "\n", usage);
+ print_err("Couldn't parse argument: ", argv[i], " ", argv[i + 1], "\n", usage);
}
goto next_flag;
}
@@ -370,7 +344,7 @@ public void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help,
exit(0);
}
print_err("Unrecognized flag: ", flag, "\n", usage);
- next_flag:;
+ next_flag:;
}
} else {
// Handle positional args later
@@ -378,7 +352,7 @@ public void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help,
continue;
}
- next_arg:
+ next_arg:
while (used_args[i] && i < argc)
i += 1;
}
@@ -393,10 +367,9 @@ public void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help,
if (used_args[i]) continue;
while (populated_args[s]) {
- next_non_bool_flag:
+ next_non_bool_flag:
++s;
- if (s >= spec_len)
- print_err("Extra argument: ", argv[i], "\n", usage);
+ if (s >= spec_len) print_err("Extra argument: ", argv[i], "\n", usage);
}
const TypeInfo_t *non_opt_type = spec[s].type;
@@ -404,45 +377,40 @@ public void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help,
non_opt_type = non_opt_type->OptionalInfo.type;
// You can't specify boolean flags positionally
- if (non_opt_type == &Bool$info)
- goto next_non_bool_flag;
+ if (non_opt_type == &Bool$info) goto next_non_bool_flag;
if (non_opt_type->tag == ListInfo) {
int num_args = 0;
while (i + num_args < argc) {
- if (!ignore_dashes && (argv[i+num_args][0] == '-' && !isdigit(argv[i+num_args][1])))
- break;
- used_args[i+num_args] = true;
+ if (!ignore_dashes && (argv[i + num_args][0] == '-' && !isdigit(argv[i + num_args][1]))) break;
+ used_args[i + num_args] = true;
num_args += 1;
}
populated_args[s] = true;
- *(OptionalList_t*)spec[s].dest = parse_list(non_opt_type->ListInfo.item, num_args, &argv[i]);
+ *(OptionalList_t *)spec[s].dest = parse_list(non_opt_type->ListInfo.item, num_args, &argv[i]);
} else if (non_opt_type->tag == TableInfo) {
int num_args = 0;
while (i + num_args < argc) {
- if ((argv[i+num_args][0] == '-' && !isdigit(argv[i+num_args][1])) || !strchr(argv[i+num_args], '='))
+ if ((argv[i + num_args][0] == '-' && !isdigit(argv[i + num_args][1]))
+ || !strchr(argv[i + num_args], '='))
break;
- used_args[i+num_args] = true;
+ used_args[i + num_args] = true;
num_args += 1;
}
populated_args[s] = true;
- *(OptionalTable_t*)spec[s].dest = parse_table(non_opt_type, num_args, &argv[i]);
+ *(OptionalTable_t *)spec[s].dest = parse_table(non_opt_type, num_args, &argv[i]);
} else {
populated_args[s] = parse_single_arg(spec[s].type, argv[i], spec[s].dest);
}
- if (!populated_args[s])
- print_err("Invalid value for ", spec[s].name, ": ", argv[i], "\n", usage);
+ if (!populated_args[s]) print_err("Invalid value for ", spec[s].name, ": ", argv[i], "\n", usage);
}
for (int s = 0; s < spec_len; s++) {
if (!populated_args[s] && spec[s].required) {
- if (spec[s].type->tag == ListInfo)
- *(OptionalList_t*)spec[s].dest = (List_t){};
- else if (spec[s].type->tag == TableInfo)
- *(OptionalTable_t*)spec[s].dest = (Table_t){};
- else
- print_err("The required argument '", spec[s].name, "' was not provided\n", usage);
+ if (spec[s].type->tag == ListInfo) *(OptionalList_t *)spec[s].dest = (List_t){};
+ else if (spec[s].type->tag == TableInfo) *(OptionalTable_t *)spec[s].dest = (Table_t){};
+ else print_err("The required argument '", spec[s].name, "' was not provided\n", usage);
}
}
}
@@ -450,24 +418,18 @@ public void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help,
#pragma GCC diagnostic pop
#endif
-public _Noreturn void fail_text(Text_t message)
-{
- fail(message);
-}
+public
+_Noreturn void fail_text(Text_t message) { fail(message); }
-public Text_t builtin_last_err()
-{
- return Text$from_str(strerror(errno));
-}
+public
+Text_t builtin_last_err() { return Text$from_str(strerror(errno)); }
static int _inspect_depth = 0;
static file_t *file = NULL;
-__attribute__((nonnull))
-public void start_inspect(const char *filename, int64_t start, int64_t end)
-{
- if (file == NULL || strcmp(file->filename, filename) != 0)
- file = load_file(filename);
+__attribute__((nonnull)) public
+void start_inspect(const char *filename, int64_t start, int64_t end) {
+ if (file == NULL || strcmp(file->filename, filename) != 0) file = load_file(filename);
if (file) {
size_t first_line_len = strcspn(file->text + start, "\r\n");
@@ -476,26 +438,25 @@ public void start_inspect(const char *filename, int64_t start, int64_t end)
int64_t line_num = get_line_number(file, file->text + start);
if (USE_COLOR) {
- print(repeated_char(' ', 3*_inspect_depth), "\x1b[33;1m>> \x1b[m",
- string_slice(file->text + start, first_line_len),
- " ", repeated_char(' ', MAX(0, 35-(int64_t)first_line_len-3*_inspect_depth)),
- "\x1b[32;2m[", file_base, ":", line_num, "]\x1b[m");
+ print(repeated_char(' ', 3 * _inspect_depth), "\x1b[33;1m>> \x1b[m",
+ string_slice(file->text + start, first_line_len), " ",
+ repeated_char(' ', MAX(0, 35 - (int64_t)first_line_len - 3 * _inspect_depth)), "\x1b[32;2m[",
+ file_base, ":", line_num, "]\x1b[m");
} else {
- print(repeated_char(' ', 3*_inspect_depth), ">> ",
- string_slice(file->text + start, first_line_len),
- " ", repeated_char(' ', MAX(0, 35-(int64_t)first_line_len-3*_inspect_depth)),
- "[", file_base, ":", line_num, "]");
+ print(repeated_char(' ', 3 * _inspect_depth), ">> ", string_slice(file->text + start, first_line_len),
+ " ", repeated_char(' ', MAX(0, 35 - (int64_t)first_line_len - 3 * _inspect_depth)), "[", file_base,
+ ":", line_num, "]");
}
// For multi-line expressions, dedent each and print it on a new line with ".. " in front:
if (end > start + (int64_t)first_line_len) {
const char *line_start = get_line(file, line_num);
int64_t indent_len = (int64_t)strspn(line_start, " \t");
- for (const char *line = file->text + start + first_line_len; line < file->text + end; line += strcspn(line, "\r\n")) {
+ for (const char *line = file->text + start + first_line_len; line < file->text + end;
+ line += strcspn(line, "\r\n")) {
line += strspn(line, "\r\n");
- if ((int64_t)strspn(line, " \t") >= indent_len)
- line += indent_len;
- print(repeated_char(' ', 3*_inspect_depth), USE_COLOR ? "\x1b[33m.. " : ".. ",
+ if ((int64_t)strspn(line, " \t") >= indent_len) line += indent_len;
+ print(repeated_char(' ', 3 * _inspect_depth), USE_COLOR ? "\x1b[33m.. " : ".. ",
string_slice(line, strcspn(line, "\r\n")));
}
}
@@ -503,23 +464,24 @@ public void start_inspect(const char *filename, int64_t start, int64_t end)
_inspect_depth += 1;
}
-public void end_inspect(const void *expr, const TypeInfo_t *type)
-{
+public
+void end_inspect(const void *expr, const TypeInfo_t *type) {
_inspect_depth -= 1;
if (type && type->metamethods.as_text) {
Text_t expr_text = generic_as_text(expr, USE_COLOR, type);
Text_t type_name = generic_as_text(NULL, false, type);
- for (int i = 0; i < 3*_inspect_depth; i++) fputc(' ', stdout);
- fprint(stdout, USE_COLOR ? "\x1b[33;1m=\x1b[0m " : "= ", expr_text, USE_COLOR ? " \x1b[2m: \x1b[36m" : " : ", type_name, USE_COLOR ? "\033[m" : "");
+ for (int i = 0; i < 3 * _inspect_depth; i++)
+ fputc(' ', stdout);
+ fprint(stdout, USE_COLOR ? "\x1b[33;1m=\x1b[0m " : "= ", expr_text, USE_COLOR ? " \x1b[2m: \x1b[36m" : " : ",
+ type_name, USE_COLOR ? "\033[m" : "");
}
}
-__attribute__((nonnull))
-public void test_value(const char *filename, int64_t start, int64_t end, const void *expr, const void *expected, const TypeInfo_t *type)
-{
- if (generic_equal(expr, expected, type))
- return;
+__attribute__((nonnull)) public
+void test_value(const char *filename, int64_t start, int64_t end, const void *expr, const void *expected,
+ const TypeInfo_t *type) {
+ if (generic_equal(expr, expected, type)) return;
print_stacktrace(stderr, 2);
fprint(stderr, "");
@@ -532,38 +494,42 @@ public void test_value(const char *filename, int64_t start, int64_t end, const v
Text_t expr_text = generic_as_text(expr, USE_COLOR, type);
Text_t expected_text = generic_as_text(expected, USE_COLOR, type);
if (USE_COLOR) {
- fprint(stderr,
- "\n\x1b[31;7m ==================== TEST FAILED ==================== \x1b[0;1m\n\n"
- "You expected: \x1b[m", expected_text, "\x1b[0m\n"
- "\x1b[1m But I got:\x1b[m ", expr_text, "\n");
+ fprint(stderr,
+ "\n\x1b[31;7m ==================== TEST FAILED ==================== \x1b[0;1m\n\n"
+ "You expected: \x1b[m",
+ expected_text,
+ "\x1b[0m\n"
+ "\x1b[1m But I got:\x1b[m ",
+ expr_text, "\n");
} else {
- fprint(stderr,
- "\n==================== TEST FAILED ====================\n\n"
- "You expected: ", expected_text, "\n"
- " But I got: ", expr_text, "\n");
+ fprint(stderr,
+ "\n==================== TEST FAILED ====================\n\n"
+ "You expected: ",
+ expected_text,
+ "\n"
+ " But I got: ",
+ expr_text, "\n");
}
fflush(stderr);
raise(SIGABRT);
}
-public void say(Text_t text, bool newline)
-{
+public
+void say(Text_t text, bool newline) {
Text$print(stdout, text);
- if (newline)
- fputc('\n', stdout);
+ if (newline) fputc('\n', stdout);
fflush(stdout);
}
-public _Noreturn void tomo_exit(Text_t text, int32_t status)
-{
- if (text.length > 0)
- print(text);
+public
+_Noreturn void tomo_exit(Text_t text, int32_t status) {
+ if (text.length > 0) print(text);
_exit(status);
}
-public OptionalText_t ask(Text_t prompt, bool bold, bool force_tty)
-{
+public
+OptionalText_t ask(Text_t prompt, bool bold, bool force_tty) {
OptionalText_t ret = NONE_TEXT;
FILE *out = stdout;
FILE *in = stdin;
@@ -597,8 +563,8 @@ public OptionalText_t ask(Text_t prompt, bool bold, bool force_tty)
goto cleanup;
}
- if (length > 0 && line[length-1] == '\n') {
- line[length-1] = '\0';
+ if (length > 0 && line[length - 1] == '\n') {
+ line[length - 1] = '\0';
--length;
}
@@ -607,14 +573,14 @@ public OptionalText_t ask(Text_t prompt, bool bold, bool force_tty)
ret = Text$from_strn(gc_input, (size_t)(length));
- cleanup:
+cleanup:
if (out && out != stdout) fclose(out);
if (in && in != stdin) fclose(in);
return ret;
}
-public bool pop_flag(char **argv, int *i, const char *flag, Text_t *result)
-{
+public
+bool pop_flag(char **argv, int *i, const char *flag, Text_t *result) {
if (argv[*i][0] != '-' || argv[*i][1] != '-') {
return false;
} else if (streq(argv[*i] + 2, flag)) {
@@ -637,23 +603,21 @@ public bool pop_flag(char **argv, int *i, const char *flag, Text_t *result)
}
}
-public void sleep_num(double seconds)
-{
+public
+void sleep_num(double seconds) {
struct timespec ts;
ts.tv_sec = (time_t)seconds;
ts.tv_nsec = (long)((seconds - (double)ts.tv_sec) * 1e9);
nanosleep(&ts, NULL);
}
-public OptionalText_t getenv_text(Text_t name)
-{
+public
+OptionalText_t getenv_text(Text_t name) {
const char *val = getenv(Text$as_c_string(name));
return val ? Text$from_str(val) : NONE_TEXT;
}
-public void setenv_text(Text_t name, Text_t value)
-{
- setenv(Text$as_c_string(name), Text$as_c_string(value), 1);
-}
+public
+void setenv_text(Text_t name, Text_t value) { setenv(Text$as_c_string(name), Text$as_c_string(value), 1); }
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/stdlib/stdlib.h b/src/stdlib/stdlib.h
index 8ac35f72..c676beb1 100644
--- a/src/stdlib/stdlib.h
+++ b/src/stdlib/stdlib.h
@@ -23,66 +23,72 @@ typedef struct {
} cli_arg_t;
void tomo_init(void);
-void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help, const char *version, int spec_len, cli_arg_t spec[spec_len]);
-#define tomo_parse_args(argc, argv, usage, help, version, ...) \
- _tomo_parse_args(argc, argv, usage, help, version, sizeof((cli_arg_t[]){__VA_ARGS__})/sizeof(cli_arg_t), (cli_arg_t[]){__VA_ARGS__})
+void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help, const char *version, int spec_len,
+ cli_arg_t spec[spec_len]);
+#define tomo_parse_args(argc, argv, usage, help, version, ...) \
+ _tomo_parse_args(argc, argv, usage, help, version, sizeof((cli_arg_t[]){__VA_ARGS__}) / sizeof(cli_arg_t), \
+ (cli_arg_t[]){__VA_ARGS__})
-#define fail(...) ({ \
- fflush(stdout); \
- if (USE_COLOR) fputs("\x1b[31;7m ==================== ERROR ==================== \033[m\n\n", stderr); \
- else fputs("==================== ERROR ====================\n\n", stderr); \
- print_stacktrace(stderr, 1); \
- if (USE_COLOR) fputs("\n\x1b[31;1m", stderr); \
- else fputs("\n", stderr); \
- fprint_inline(stderr, "Error: ", __VA_ARGS__); \
- if (USE_COLOR) fputs("\x1b[m\n", stderr); \
- else fputs("\n", stderr); \
- fflush(stderr); \
- raise(SIGABRT); \
- _exit(1); \
-})
+#define fail(...) \
+ ({ \
+ fflush(stdout); \
+ if (USE_COLOR) fputs("\x1b[31;7m ==================== ERROR ==================== \033[m\n\n", stderr); \
+ else fputs("==================== ERROR ====================\n\n", stderr); \
+ print_stacktrace(stderr, 1); \
+ if (USE_COLOR) fputs("\n\x1b[31;1m", stderr); \
+ else fputs("\n", stderr); \
+ fprint_inline(stderr, "Error: ", __VA_ARGS__); \
+ if (USE_COLOR) fputs("\x1b[m\n", stderr); \
+ else fputs("\n", stderr); \
+ fflush(stderr); \
+ raise(SIGABRT); \
+ _exit(1); \
+ })
-#define fail_source(filename, start, end, ...) ({ \
- fflush(stdout); \
- if (USE_COLOR) fputs("\x1b[31;7m ==================== ERROR ==================== \n\n\x1b[0;1m", stderr); \
- else fputs("==================== ERROR ====================\n\n", stderr); \
- print_stacktrace(stderr, 0); \
- fputs("\n", stderr); \
- if (USE_COLOR) fputs("\x1b[31;1m", stderr); \
- fprint_inline(stderr, __VA_ARGS__); \
- file_t *_file = (filename) ? load_file(filename) : NULL; \
- if ((filename) && _file) { \
- fputs("\n", stderr); \
- highlight_error(_file, _file->text+(start), _file->text+(end), "\x1b[31;1m", 1, USE_COLOR); \
- } \
- if (USE_COLOR) fputs("\x1b[m", stderr); \
- fflush(stderr); \
- raise(SIGABRT); \
- _exit(1); \
-})
+#define fail_source(filename, start, end, ...) \
+ ({ \
+ fflush(stdout); \
+ if (USE_COLOR) fputs("\x1b[31;7m ==================== ERROR ==================== \n\n\x1b[0;1m", stderr); \
+ else fputs("==================== ERROR ====================\n\n", stderr); \
+ print_stacktrace(stderr, 0); \
+ fputs("\n", stderr); \
+ if (USE_COLOR) fputs("\x1b[31;1m", stderr); \
+ fprint_inline(stderr, __VA_ARGS__); \
+ file_t *_file = (filename) ? load_file(filename) : NULL; \
+ if ((filename) && _file) { \
+ fputs("\n", stderr); \
+ highlight_error(_file, _file->text + (start), _file->text + (end), "\x1b[31;1m", 1, USE_COLOR); \
+ } \
+ if (USE_COLOR) fputs("\x1b[m", stderr); \
+ fflush(stderr); \
+ raise(SIGABRT); \
+ _exit(1); \
+ })
_Noreturn void fail_text(Text_t message);
Text_t builtin_last_err();
-__attribute__((nonnull))
-void start_inspect(const char *filename, int64_t start, int64_t end);
+__attribute__((nonnull)) void start_inspect(const char *filename, int64_t start, int64_t end);
void end_inspect(const void *expr, const TypeInfo_t *type);
-#define inspect(type, expr, typeinfo, start, end) {\
- start_inspect(__SOURCE_FILE__, start, end); \
- type _expr = expr; \
- end_inspect(&_expr, typeinfo); \
-}
-#define inspect_void(expr, typeinfo, start, end) {\
- start_inspect(__SOURCE_FILE__, start, end); \
- expr; \
- end_inspect(NULL, typeinfo); \
-}
-__attribute__((nonnull))
-void test_value(const char *filename, int64_t start, int64_t end, const void *expr, const void *expected, const TypeInfo_t *type);
-#define test(type, expr, expected, typeinfo, start, end) {\
- type _expr = expr; \
- type _expected = expected; \
- test_value(__SOURCE_FILE__, start, end, &_expr, &_expected, typeinfo); \
-}
+#define inspect(type, expr, typeinfo, start, end) \
+ { \
+ start_inspect(__SOURCE_FILE__, start, end); \
+ type _expr = expr; \
+ end_inspect(&_expr, typeinfo); \
+ }
+#define inspect_void(expr, typeinfo, start, end) \
+ { \
+ start_inspect(__SOURCE_FILE__, start, end); \
+ expr; \
+ end_inspect(NULL, typeinfo); \
+ }
+__attribute__((nonnull)) void test_value(const char *filename, int64_t start, int64_t end, const void *expr,
+ const void *expected, const TypeInfo_t *type);
+#define test(type, expr, expected, typeinfo, start, end) \
+ { \
+ type _expr = expr; \
+ type _expected = expected; \
+ test_value(__SOURCE_FILE__, start, end, &_expr, &_expected, typeinfo); \
+ }
void say(Text_t text, bool newline);
Text_t ask(Text_t prompt, bool bold, bool force_tty);
diff --git a/src/stdlib/structs.c b/src/stdlib/structs.c
index 5d6b2319..d2300b74 100644
--- a/src/stdlib/structs.c
+++ b/src/stdlib/structs.c
@@ -13,13 +13,10 @@
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstack-protector"
#endif
-PUREFUNC public uint64_t Struct$hash(const void *obj, const TypeInfo_t *type)
-{
- if (type->StructInfo.num_fields == 0)
- return 0;
+PUREFUNC public uint64_t Struct$hash(const void *obj, const TypeInfo_t *type) {
+ if (type->StructInfo.num_fields == 0) return 0;
- if (type->StructInfo.num_fields == 1)
- return generic_hash(obj, type->StructInfo.fields[0].type);
+ if (type->StructInfo.num_fields == 1) return generic_hash(obj, type->StructInfo.fields[0].type);
uint64_t field_hashes[type->StructInfo.num_fields];
ptrdiff_t byte_offset = 0;
@@ -27,7 +24,7 @@ PUREFUNC public uint64_t Struct$hash(const void *obj, const TypeInfo_t *type)
for (int i = 0; i < type->StructInfo.num_fields; i++) {
NamedType_t field = type->StructInfo.fields[i];
if (field.type == &Bool$info) {
- bool b = ((*(char*)(obj + byte_offset)) >> bit_offset) & 0x1;
+ bool b = ((*(char *)(obj + byte_offset)) >> bit_offset) & 0x1;
field_hashes[i] = (uint32_t)b;
bit_offset += 1;
if (bit_offset >= 8) {
@@ -45,34 +42,29 @@ PUREFUNC public uint64_t Struct$hash(const void *obj, const TypeInfo_t *type)
byte_offset += field.type->size;
}
}
- return siphash24((void*)field_hashes, sizeof(field_hashes));
+ return siphash24((void *)field_hashes, sizeof(field_hashes));
}
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
-PUREFUNC public uint64_t PackedData$hash(const void *obj, const TypeInfo_t *type)
-{
- if (type->StructInfo.num_fields == 0)
- return 0;
+PUREFUNC public uint64_t PackedData$hash(const void *obj, const TypeInfo_t *type) {
+ if (type->StructInfo.num_fields == 0) return 0;
return siphash24(obj, (size_t)type->size);
}
-PUREFUNC public int32_t Struct$compare(const void *x, const void *y, const TypeInfo_t *type)
-{
- if (x == y)
- return 0;
+PUREFUNC public int32_t Struct$compare(const void *x, const void *y, const TypeInfo_t *type) {
+ if (x == y) return 0;
ptrdiff_t byte_offset = 0;
ptrdiff_t bit_offset = 0;
for (int i = 0; i < type->StructInfo.num_fields; i++) {
NamedType_t field = type->StructInfo.fields[i];
if (field.type == &Bool$info) {
- bool bx = ((*(char*)(x + byte_offset)) >> bit_offset) & 0x1;
- bool by = ((*(char*)(y + byte_offset)) >> bit_offset) & 0x1;
- if (bx != by)
- return (int32_t)bx - (int32_t)by;
+ bool bx = ((*(char *)(x + byte_offset)) >> bit_offset) & 0x1;
+ bool by = ((*(char *)(y + byte_offset)) >> bit_offset) & 0x1;
+ if (bx != by) return (int32_t)bx - (int32_t)by;
bit_offset += 1;
if (bit_offset >= 8) {
byte_offset += 1;
@@ -86,28 +78,24 @@ PUREFUNC public int32_t Struct$compare(const void *x, const void *y, const TypeI
if (field.type->align && byte_offset % field.type->align > 0)
byte_offset += field.type->align - (byte_offset % field.type->align);
int32_t cmp = generic_compare(x + byte_offset, y + byte_offset, field.type);
- if (cmp != 0)
- return cmp;
+ if (cmp != 0) return cmp;
byte_offset += field.type->size;
}
}
return 0;
}
-PUREFUNC public bool Struct$equal(const void *x, const void *y, const TypeInfo_t *type)
-{
- if (x == y)
- return true;
+PUREFUNC public bool Struct$equal(const void *x, const void *y, const TypeInfo_t *type) {
+ if (x == y) return true;
ptrdiff_t byte_offset = 0;
ptrdiff_t bit_offset = 0;
for (int i = 0; i < type->StructInfo.num_fields; i++) {
NamedType_t field = type->StructInfo.fields[i];
if (field.type == &Bool$info) {
- bool bx = ((*(char*)(x + byte_offset)) >> bit_offset) & 0x1;
- bool by = ((*(char*)(y + byte_offset)) >> bit_offset) & 0x1;
- if (bx != by)
- return false;
+ bool bx = ((*(char *)(x + byte_offset)) >> bit_offset) & 0x1;
+ bool by = ((*(char *)(y + byte_offset)) >> bit_offset) & 0x1;
+ if (bx != by) return false;
bit_offset += 1;
if (bit_offset >= 8) {
byte_offset += 1;
@@ -120,22 +108,19 @@ PUREFUNC public bool Struct$equal(const void *x, const void *y, const TypeInfo_t
}
if (field.type->align && byte_offset % field.type->align > 0)
byte_offset += field.type->align - (byte_offset % field.type->align);
- if (!generic_equal(x + byte_offset, y + byte_offset, field.type))
- return false;
+ if (!generic_equal(x + byte_offset, y + byte_offset, field.type)) return false;
byte_offset += field.type->size;
}
}
return true;
}
-PUREFUNC public bool PackedData$equal(const void *x, const void *y, const TypeInfo_t *type)
-{
+PUREFUNC public bool PackedData$equal(const void *x, const void *y, const TypeInfo_t *type) {
if (x == y) return true;
return (memcmp(x, y, (size_t)type->size) == 0);
}
-PUREFUNC public Text_t Struct$as_text(const void *obj, bool colorize, const TypeInfo_t *type)
-{
+PUREFUNC public Text_t Struct$as_text(const void *obj, bool colorize, const TypeInfo_t *type) {
if (!obj) return Text$from_str(type->StructInfo.name);
Text_t name = Text$from_str(type->StructInfo.name);
@@ -148,15 +133,14 @@ PUREFUNC public Text_t Struct$as_text(const void *obj, bool colorize, const Type
ptrdiff_t bit_offset = 0;
for (int i = 0; i < type->StructInfo.num_fields; i++) {
NamedType_t field = type->StructInfo.fields[i];
- if (i > 0)
- text = Text$concat(text, Text(", "));
+ if (i > 0) text = Text$concat(text, Text(", "));
- if (type->StructInfo.num_fields > 1)
- text = Text$concat(text, Text$from_str(field.name), Text("="));
+ if (type->StructInfo.num_fields > 1) text = Text$concat(text, Text$from_str(field.name), Text("="));
if (field.type == &Bool$info) {
- bool b = ((*(char*)(obj + byte_offset)) >> bit_offset) & 0x1;
- text = Text$concat(text, Text$from_str(colorize ? (b ? "\x1b[35myes\x1b[m" : "\x1b[35mno\x1b[m") : (b ? "yes" : "no")));
+ bool b = ((*(char *)(obj + byte_offset)) >> bit_offset) & 0x1;
+ text = Text$concat(
+ text, Text$from_str(colorize ? (b ? "\x1b[35myes\x1b[m" : "\x1b[35mno\x1b[m") : (b ? "yes" : "no")));
bit_offset += 1;
if (bit_offset >= 8) {
byte_offset += 1;
@@ -176,19 +160,16 @@ PUREFUNC public Text_t Struct$as_text(const void *obj, bool colorize, const Type
return Text$concat(text, Text(")"));
}
-PUREFUNC public bool Struct$is_none(const void *obj, const TypeInfo_t *type)
-{
- return *(bool*)(obj + type->size);
-}
+PUREFUNC public bool Struct$is_none(const void *obj, const TypeInfo_t *type) { return *(bool *)(obj + type->size); }
-public void Struct$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type)
-{
+public
+void Struct$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type) {
ptrdiff_t byte_offset = 0;
ptrdiff_t bit_offset = 0;
for (int i = 0; i < type->StructInfo.num_fields; i++) {
NamedType_t field = type->StructInfo.fields[i];
if (field.type == &Bool$info) {
- bool b = ((*(char*)(obj + byte_offset)) >> bit_offset) & 0x1;
+ bool b = ((*(char *)(obj + byte_offset)) >> bit_offset) & 0x1;
fputc((int)b, out);
bit_offset += 1;
if (bit_offset >= 8) {
@@ -208,15 +189,15 @@ public void Struct$serialize(const void *obj, FILE *out, Table_t *pointers, cons
}
}
-public void Struct$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *type)
-{
+public
+void Struct$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *type) {
ptrdiff_t byte_offset = 0;
ptrdiff_t bit_offset = 0;
for (int i = 0; i < type->StructInfo.num_fields; i++) {
NamedType_t field = type->StructInfo.fields[i];
if (field.type == &Bool$info) {
bool b = (bool)fgetc(in);
- *(char*)(outval + byte_offset) |= (b << bit_offset);
+ *(char *)(outval + byte_offset) |= (b << bit_offset);
bit_offset += 1;
if (bit_offset >= 8) {
byte_offset += 1;
diff --git a/src/stdlib/structs.h b/src/stdlib/structs.h
index c9c6c40a..03c051ec 100644
--- a/src/stdlib/structs.h
+++ b/src/stdlib/structs.h
@@ -17,24 +17,26 @@ PUREFUNC bool Struct$is_none(const void *obj, const TypeInfo_t *type);
void Struct$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type);
void Struct$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *type);
-#define Struct$metamethods { \
- .hash=Struct$hash, \
- .compare=Struct$compare, \
- .equal=Struct$equal, \
- .as_text=Struct$as_text, \
- .is_none=Struct$is_none, \
- .serialize=Struct$serialize, \
- .deserialize=Struct$deserialize, \
-}
+#define Struct$metamethods \
+ { \
+ .hash = Struct$hash, \
+ .compare = Struct$compare, \
+ .equal = Struct$equal, \
+ .as_text = Struct$as_text, \
+ .is_none = Struct$is_none, \
+ .serialize = Struct$serialize, \
+ .deserialize = Struct$deserialize, \
+ }
-#define PackedData$metamethods { \
- .hash=PackedData$hash, \
- .compare=Struct$compare, \
- .equal=PackedData$equal, \
- .as_text=Struct$as_text, \
- .is_none=Struct$is_none, \
- .serialize=Struct$serialize, \
- .deserialize=Struct$deserialize, \
-}
+#define PackedData$metamethods \
+ { \
+ .hash = PackedData$hash, \
+ .compare = Struct$compare, \
+ .equal = PackedData$equal, \
+ .as_text = Struct$as_text, \
+ .is_none = Struct$is_none, \
+ .serialize = Struct$serialize, \
+ .deserialize = Struct$deserialize, \
+ }
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/stdlib/tables.c b/src/stdlib/tables.c
index 63f8eb09..781da415 100644
--- a/src/stdlib/tables.c
+++ b/src/stdlib/tables.c
@@ -41,29 +41,29 @@
#define EQUAL_KEYS(x, y) (generic_equal((x), (y), type->TableInfo.key))
#define END_OF_CHAIN UINT32_MAX
-#define GET_ENTRY(t, i) ((t).entries.data + (t).entries.stride*(i))
+#define GET_ENTRY(t, i) ((t).entries.data + (t).entries.stride * (i))
static TypeInfo_t MemoryPointer = {
- .size=sizeof(void*),
- .align=__alignof__(void*),
- .tag=PointerInfo,
- .PointerInfo={
- .sigil="@",
- .pointed=&Memory$info,
- },
- .metamethods=Pointer$metamethods,
+ .size = sizeof(void *),
+ .align = __alignof__(void *),
+ .tag = PointerInfo,
+ .PointerInfo =
+ {
+ .sigil = "@",
+ .pointed = &Memory$info,
+ },
+ .metamethods = Pointer$metamethods,
};
const TypeInfo_t CStrToVoidStarTable = {
- .size=sizeof(Table_t),
- .align=__alignof__(Table_t),
- .tag=TableInfo,
- .TableInfo={.key=&CString$info, .value=&MemoryPointer},
- .metamethods=Table$metamethods,
+ .size = sizeof(Table_t),
+ .align = __alignof__(Table_t),
+ .tag = TableInfo,
+ .TableInfo = {.key = &CString$info, .value = &MemoryPointer},
+ .metamethods = Table$metamethods,
};
-PUREFUNC static INLINE size_t entry_size(const TypeInfo_t *info)
-{
+PUREFUNC static INLINE size_t entry_size(const TypeInfo_t *info) {
size_t size = (size_t)info->TableInfo.key->size;
if (info->TableInfo.value->align > 1 && size % (size_t)info->TableInfo.value->align)
size += (size_t)info->TableInfo.value->align - (size % (size_t)info->TableInfo.value->align); // padding
@@ -73,31 +73,27 @@ PUREFUNC static INLINE size_t entry_size(const TypeInfo_t *info)
return size;
}
-PUREFUNC static INLINE size_t value_offset(const TypeInfo_t *info)
-{
+PUREFUNC static INLINE size_t value_offset(const TypeInfo_t *info) {
size_t offset = (size_t)info->TableInfo.key->size;
if ((size_t)info->TableInfo.value->align > 1 && offset % (size_t)info->TableInfo.value->align)
offset += (size_t)info->TableInfo.value->align - (offset % (size_t)info->TableInfo.value->align); // padding
return offset;
}
-static INLINE void hshow(const Table_t *t)
-{
+static INLINE void hshow(const Table_t *t) {
hdebug("{");
for (uint32_t i = 0; t->bucket_info && i < t->bucket_info->count; i++) {
if (i > 0) hdebug(" ");
if (t->bucket_info->buckets[i].occupied)
- hdebug("[", i, "]=", (uint32_t)t->bucket_info->buckets[i].index, "(", t->bucket_info->buckets[i].next_bucket, ")");
- else
- hdebug("[", i, "]=_");
+ hdebug("[", i, "]=", (uint32_t)t->bucket_info->buckets[i].index, "(",
+ t->bucket_info->buckets[i].next_bucket, ")");
+ else hdebug("[", i, "]=_");
}
hdebug("}\n");
}
-static void maybe_copy_on_write(Table_t *t, const TypeInfo_t *type)
-{
- if (t->entries.data_refcount != 0)
- List$compact(&t->entries, (int64_t)entry_size(type));
+static void maybe_copy_on_write(Table_t *t, const TypeInfo_t *type) {
+ if (t->entries.data_refcount != 0) List$compact(&t->entries, (int64_t)entry_size(type));
if (t->bucket_info && t->bucket_info->data_refcount != 0) {
size_t size = sizeof(bucket_info_t) + sizeof(bucket_t[t->bucket_info->count]);
@@ -107,8 +103,7 @@ static void maybe_copy_on_write(Table_t *t, const TypeInfo_t *type)
}
// Return address of value or NULL
-PUREFUNC public void *Table$get_raw(Table_t t, const void *key, const TypeInfo_t *type)
-{
+PUREFUNC public void *Table$get_raw(Table_t t, const void *key, const TypeInfo_t *type) {
assert(type->tag == TableInfo);
if (!key || !t.bucket_info) return NULL;
@@ -123,14 +118,12 @@ PUREFUNC public void *Table$get_raw(Table_t t, const void *key, const TypeInfo_t
hdebug("Found key!\n");
return entry + value_offset(type);
}
- if (buckets[i].next_bucket == END_OF_CHAIN)
- break;
+ if (buckets[i].next_bucket == END_OF_CHAIN) break;
}
return NULL;
}
-PUREFUNC public void *Table$get(Table_t t, const void *key, const TypeInfo_t *type)
-{
+PUREFUNC public void *Table$get(Table_t t, const void *key, const TypeInfo_t *type) {
assert(type->tag == TableInfo);
for (const Table_t *iter = &t; iter; iter = iter->fallback) {
void *ret = Table$get_raw(*iter, key, type);
@@ -139,8 +132,7 @@ PUREFUNC public void *Table$get(Table_t t, const void *key, const TypeInfo_t *ty
return NULL;
}
-static void Table$set_bucket(Table_t *t, const void *entry, int32_t index, const TypeInfo_t *type)
-{
+static void Table$set_bucket(Table_t *t, const void *entry, int32_t index, const TypeInfo_t *type) {
assert(t->bucket_info);
hshow(t);
const void *key = entry;
@@ -182,15 +174,14 @@ static void Table$set_bucket(Table_t *t, const void *entry, int32_t index, const
bucket->next_bucket = END_OF_CHAIN;
} else { // Collided with the start of a chain, put the new entry in chain position #2
hdebug("Hit start of a chain\n");
- buckets[t->bucket_info->last_free] = (bucket_t){
- .occupied = 1, .index=index, .next_bucket=bucket->next_bucket};
+ buckets[t->bucket_info->last_free] =
+ (bucket_t){.occupied = 1, .index = index, .next_bucket = bucket->next_bucket};
bucket->next_bucket = t->bucket_info->last_free;
}
hshow(t);
}
-static void hashmap_resize_buckets(Table_t *t, uint32_t new_capacity, const TypeInfo_t *type)
-{
+static void hashmap_resize_buckets(Table_t *t, uint32_t new_capacity, const TypeInfo_t *type) {
if (unlikely(new_capacity > TABLE_MAX_BUCKETS))
fail("Table has exceeded the maximum table size (2^31) and cannot grow further!");
hdebug("About to resize from ", t->bucket_info ? (int32_t)t->bucket_info->count : 0, " to ", new_capacity, "\n");
@@ -199,7 +190,7 @@ static void hashmap_resize_buckets(Table_t *t, uint32_t new_capacity, const Type
t->bucket_info = GC_MALLOC_ATOMIC(alloc_size);
memset(t->bucket_info->buckets, 0, sizeof(bucket_t[new_capacity]));
t->bucket_info->count = new_capacity;
- t->bucket_info->last_free = new_capacity-1;
+ t->bucket_info->last_free = new_capacity - 1;
// Rehash:
for (int64_t i = 0; i < Table$length(*t); i++) {
hdebug("Rehashing ", i, "\n");
@@ -215,16 +206,15 @@ static void hashmap_resize_buckets(Table_t *t, uint32_t new_capacity, const Type
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstack-protector"
#endif
-public void *Table$reserve(Table_t *t, const void *key, const void *value, const TypeInfo_t *type)
-{
+public
+void *Table$reserve(Table_t *t, const void *key, const void *value, const TypeInfo_t *type) {
assert(type->tag == TableInfo);
if (!t || !key) return NULL;
hshow(t);
t->hash = 0;
- int64_t key_size = type->TableInfo.key->size,
- value_size = type->TableInfo.value->size;
+ int64_t key_size = type->TableInfo.key->size, value_size = type->TableInfo.value->size;
if (!t->bucket_info || t->bucket_info->count == 0) {
hashmap_resize_buckets(t, 8, type);
} else {
@@ -236,8 +226,7 @@ public void *Table$reserve(Table_t *t, const void *key, const void *value, const
maybe_copy_on_write(t, type);
value_home = t->entries.data + offset;
- if (value && value_size > 0)
- memcpy(value_home, value, (size_t)value_size);
+ if (value && value_size > 0) memcpy(value_home, value, (size_t)value_size);
return value_home;
}
@@ -247,9 +236,8 @@ public void *Table$reserve(Table_t *t, const void *key, const void *value, const
// Resize buckets if necessary
if (t->entries.length >= (int64_t)t->bucket_info->count) {
// Current resize policy: +50% at a time:
- uint32_t newsize = MAX(8, (uint32_t)(3*t->bucket_info->count)/2);
- if (unlikely(newsize > TABLE_MAX_BUCKETS))
- newsize = TABLE_MAX_BUCKETS;
+ uint32_t newsize = MAX(8, (uint32_t)(3 * t->bucket_info->count) / 2);
+ if (unlikely(newsize > TABLE_MAX_BUCKETS)) newsize = TABLE_MAX_BUCKETS;
hashmap_resize_buckets(t, newsize, type);
}
@@ -265,13 +253,11 @@ public void *Table$reserve(Table_t *t, const void *key, const void *value, const
char buf[entry_size(type)];
memset(buf, 0, sizeof(buf));
memcpy(buf, key, (size_t)key_size);
- if (value && value_size > 0)
- memcpy(buf + value_offset(type), value, (size_t)value_size);
- else if (value_size > 0)
- memset(buf + value_offset(type), 0, (size_t)value_size);
+ if (value && value_size > 0) memcpy(buf + value_offset(type), value, (size_t)value_size);
+ else if (value_size > 0) memset(buf + value_offset(type), 0, (size_t)value_size);
List$insert(&t->entries, buf, I(0), (int64_t)entry_size(type));
- int64_t entry_index = t->entries.length-1;
+ int64_t entry_index = t->entries.length - 1;
void *entry = GET_ENTRY(*t, entry_index);
Table$set_bucket(t, entry, entry_index, type);
return entry + value_offset(type);
@@ -280,14 +266,14 @@ public void *Table$reserve(Table_t *t, const void *key, const void *value, const
#pragma GCC diagnostic pop
#endif
-public void Table$set(Table_t *t, const void *key, const void *value, const TypeInfo_t *type)
-{
+public
+void Table$set(Table_t *t, const void *key, const void *value, const TypeInfo_t *type) {
assert(type->tag == TableInfo);
(void)Table$reserve(t, key, value, type);
}
-public void Table$remove(Table_t *t, const void *key, const TypeInfo_t *type)
-{
+public
+void Table$remove(Table_t *t, const void *key, const TypeInfo_t *type) {
assert(type->tag == TableInfo);
if (!t || Table$length(*t) == 0) return;
@@ -295,8 +281,7 @@ public void Table$remove(Table_t *t, const void *key, const TypeInfo_t *type)
maybe_copy_on_write(t, type);
// If unspecified, pop the last key:
- if (!key)
- key = GET_ENTRY(*t, t->entries.length-1);
+ if (!key) key = GET_ENTRY(*t, t->entries.length - 1);
// Steps: look up the bucket for the removed key
// If missing, then return immediately
@@ -322,13 +307,12 @@ public void Table$remove(Table_t *t, const void *key, const TypeInfo_t *type)
hdebug("Found key to delete in bucket ", i, "\n");
goto found_it;
}
- if (t->bucket_info->buckets[i].next_bucket == END_OF_CHAIN)
- return;
+ if (t->bucket_info->buckets[i].next_bucket == END_OF_CHAIN) return;
prev = &t->bucket_info->buckets[i];
}
return;
- found_it:;
+found_it:;
assert(bucket->occupied);
t->hash = 0;
@@ -337,7 +321,7 @@ public void Table$remove(Table_t *t, const void *key, const TypeInfo_t *type)
// swap the other entry into the last position and then remove the last
// entry. This disturbs the ordering of the table, but keeps removal O(1)
// instead of O(N)
- int64_t last_entry = t->entries.length-1;
+ int64_t last_entry = t->entries.length - 1;
if (bucket->index != last_entry) {
hdebug("Removing key/value from the middle of the entries list\n");
@@ -374,70 +358,58 @@ public void Table$remove(Table_t *t, const void *key, const TypeInfo_t *type)
}
t->bucket_info->buckets[bucket_to_clear] = (bucket_t){0};
- if (bucket_to_clear > t->bucket_info->last_free)
- t->bucket_info->last_free = bucket_to_clear;
+ if (bucket_to_clear > t->bucket_info->last_free) t->bucket_info->last_free = bucket_to_clear;
hshow(t);
}
-CONSTFUNC public void *Table$entry(Table_t t, int64_t n)
-{
- if (n < 1 || n > Table$length(t))
- return NULL;
- return GET_ENTRY(t, n-1);
+CONSTFUNC public void *Table$entry(Table_t t, int64_t n) {
+ if (n < 1 || n > Table$length(t)) return NULL;
+ return GET_ENTRY(t, n - 1);
}
-public void Table$clear(Table_t *t)
-{
- memset(t, 0, sizeof(Table_t));
-}
+public
+void Table$clear(Table_t *t) { memset(t, 0, sizeof(Table_t)); }
-public Table_t Table$sorted(Table_t t, const TypeInfo_t *type)
-{
- Closure_t cmp = (Closure_t){.fn=generic_compare, .userdata=(void*)type->TableInfo.key};
+public
+Table_t Table$sorted(Table_t t, const TypeInfo_t *type) {
+ Closure_t cmp = (Closure_t){.fn = generic_compare, .userdata = (void *)type->TableInfo.key};
List_t entries = List$sorted(t.entries, cmp, (int64_t)entry_size(type));
return Table$from_entries(entries, type);
}
-PUREFUNC public bool Table$equal(const void *vx, const void *vy, const TypeInfo_t *type)
-{
+PUREFUNC public bool Table$equal(const void *vx, const void *vy, const TypeInfo_t *type) {
if (vx == vy) return true;
- Table_t *x = (Table_t*)vx, *y = (Table_t*)vy;
+ Table_t *x = (Table_t *)vx, *y = (Table_t *)vy;
- if (x->hash && y->hash && x->hash != y->hash)
- return false;
+ if (x->hash && y->hash && x->hash != y->hash) return false;
assert(type->tag == TableInfo);
- if (x->entries.length != y->entries.length)
- return false;
-
- if ((x->fallback != NULL) != (y->fallback != NULL))
- return false;
+ if (x->entries.length != y->entries.length) return false;
+
+ if ((x->fallback != NULL) != (y->fallback != NULL)) return false;
const TypeInfo_t *value_type = type->TableInfo.value;
size_t offset = value_offset(type);
for (int64_t i = 0; i < x->entries.length; i++) {
- void *x_key = x->entries.data + i*x->entries.stride;
+ void *x_key = x->entries.data + i * x->entries.stride;
void *y_value = Table$get_raw(*y, x_key, type);
if (!y_value) return false;
void *x_value = x_key + offset;
- if (!generic_equal(y_value, x_value, value_type))
- return false;
+ if (!generic_equal(y_value, x_value, value_type)) return false;
}
return true;
}
-PUREFUNC public int32_t Table$compare(const void *vx, const void *vy, const TypeInfo_t *type)
-{
+PUREFUNC public int32_t Table$compare(const void *vx, const void *vy, const TypeInfo_t *type) {
if (vx == vy) return 0;
- Table_t *x = (Table_t*)vx, *y = (Table_t*)vy;
+ Table_t *x = (Table_t *)vx, *y = (Table_t *)vy;
assert(type->tag == TableInfo);
__typeof(type->TableInfo) table = type->TableInfo;
// Sort empty tables before non-empty tables:
- if (x->entries.length == 0 || y->entries.length == 0)
- return ((x->entries.length > 0) - (y->entries.length > 0));
+ if (x->entries.length == 0 || y->entries.length == 0) return ((x->entries.length > 0) - (y->entries.length > 0));
// Table comparison rules:
// - If two tables have different keys, then compare as if comparing a
@@ -446,22 +418,20 @@ PUREFUNC public int32_t Table$compare(const void *vx, const void *vy, const Type
// - Otherwise, compare as if comparing lists of values for the sorted key
// lists:
// `[x[k] for k in x.keys.sorted()] <> [y[k] for k in y.keys.sorted()]`
- //
+ //
// We can do this in _linear_ time if we find the smallest `k` such that
// `x[k] != y[k]`, as well as the largest key in `x` and `y`.
void *mismatched_key = NULL, *max_x_key = NULL;
for (int64_t i = 0; i < x->entries.length; i++) {
void *key = x->entries.data + x->entries.stride * i;
- if (max_x_key == NULL || generic_compare(key, max_x_key, table.key) > 0)
- max_x_key = key;
+ if (max_x_key == NULL || generic_compare(key, max_x_key, table.key) > 0) max_x_key = key;
void *x_value = key + value_offset(type);
void *y_value = Table$get_raw(*y, key, type);
if (!y_value || (table.value->size > 0 && !generic_equal(x_value, y_value, table.value))) {
- if (mismatched_key == NULL || generic_compare(key, mismatched_key, table.key) < 0)
- mismatched_key = key;
+ if (mismatched_key == NULL || generic_compare(key, mismatched_key, table.key) < 0) mismatched_key = key;
}
}
@@ -470,14 +440,12 @@ PUREFUNC public int32_t Table$compare(const void *vx, const void *vy, const Type
void *max_y_key = NULL;
for (int64_t i = 0; i < y->entries.length; i++) {
void *key = y->entries.data + y->entries.stride * i;
- if (max_y_key == NULL || generic_compare(key, max_y_key, table.key) > 0)
- max_y_key = key;
+ if (max_y_key == NULL || generic_compare(key, max_y_key, table.key) > 0) max_y_key = key;
void *y_value = key + value_offset(type);
void *x_value = Table$get_raw(*x, key, type);
if (!x_value || !generic_equal(x_value, y_value, table.value)) {
- if (mismatched_key == NULL || generic_compare(key, mismatched_key, table.key) < 0)
- mismatched_key = key;
+ if (mismatched_key == NULL || generic_compare(key, mismatched_key, table.key) < 0) mismatched_key = key;
}
}
@@ -529,12 +497,10 @@ PUREFUNC public int32_t Table$compare(const void *vx, const void *vy, const Type
return 0;
}
-PUREFUNC public uint64_t Table$hash(const void *obj, const TypeInfo_t *type)
-{
+PUREFUNC public uint64_t Table$hash(const void *obj, const TypeInfo_t *type) {
assert(type->tag == TableInfo);
- Table_t *t = (Table_t*)obj;
- if (t->hash != 0)
- return t->hash;
+ Table_t *t = (Table_t *)obj;
+ if (t->hash != 0) return t->hash;
// Table hashes are computed as:
// hash(t.length, (xor: t.keys), (xor: t.values), t.fallback)
@@ -544,12 +510,12 @@ PUREFUNC public uint64_t Table$hash(const void *obj, const TypeInfo_t *type)
size_t offset = value_offset(type);
if (table.value->size > 0) {
for (int64_t i = 0; i < t->entries.length; i++) {
- keys_hash ^= generic_hash(t->entries.data + i*t->entries.stride, table.key);
- values_hash ^= generic_hash(t->entries.data + i*t->entries.stride + offset, table.value);
+ keys_hash ^= generic_hash(t->entries.data + i * t->entries.stride, table.key);
+ values_hash ^= generic_hash(t->entries.data + i * t->entries.stride + offset, table.value);
}
} else {
for (int64_t i = 0; i < t->entries.length; i++)
- keys_hash ^= generic_hash(t->entries.data + i*t->entries.stride, table.key);
+ keys_hash ^= generic_hash(t->entries.data + i * t->entries.stride, table.key);
}
volatile struct {
@@ -561,41 +527,31 @@ PUREFUNC public uint64_t Table$hash(const void *obj, const TypeInfo_t *type)
values_hash,
t->fallback ? Table$hash(t->fallback, type) : 0,
};
- t->hash = siphash24((void*)&components, sizeof(components));
- if unlikely (t->hash == 0)
- t->hash = 1234567;
+ t->hash = siphash24((void *)&components, sizeof(components));
+ if unlikely (t->hash == 0) t->hash = 1234567;
return t->hash;
}
-public Text_t Table$as_text(const void *obj, bool colorize, const TypeInfo_t *type)
-{
- Table_t *t = (Table_t*)obj;
+public
+Text_t Table$as_text(const void *obj, bool colorize, const TypeInfo_t *type) {
+ Table_t *t = (Table_t *)obj;
assert(type->tag == TableInfo);
__typeof(type->TableInfo) table = type->TableInfo;
if (!t) {
- if (table.value != &Void$info)
- return Text$concat(
- Text("{"),
- generic_as_text(NULL, false, table.key),
- Text("="),
- generic_as_text(NULL, false, table.value),
- Text("}"));
- else
- return Text$concat(
- Text("|"),
- generic_as_text(NULL, false, table.key),
- Text("|"));
+ if (table.value != &Void$info)
+ return Text$concat(Text("{"), generic_as_text(NULL, false, table.key), Text("="),
+ generic_as_text(NULL, false, table.value), Text("}"));
+ else return Text$concat(Text("|"), generic_as_text(NULL, false, table.key), Text("|"));
}
int64_t val_off = (int64_t)value_offset(type);
Text_t text = table.value == &Void$info ? Text("|") : Text("{");
for (int64_t i = 0, length = Table$length(*t); i < length; i++) {
- if (i > 0)
- text = Text$concat(text, Text(", "));
+ if (i > 0) text = Text$concat(text, Text(", "));
void *entry = GET_ENTRY(*t, i);
text = Text$concat(text, generic_as_text(entry, colorize, table.key));
- if (table.value != &Void$info)
+ if (table.value != &Void$info)
text = Text$concat(text, Text("="), generic_as_text(entry + val_off, colorize, table.value));
}
@@ -607,11 +563,10 @@ public Text_t Table$as_text(const void *obj, bool colorize, const TypeInfo_t *ty
return text;
}
-public Table_t Table$from_entries(List_t entries, const TypeInfo_t *type)
-{
+public
+Table_t Table$from_entries(List_t entries, const TypeInfo_t *type) {
assert(type->tag == TableInfo);
- if (entries.length == 0)
- return (Table_t){};
+ if (entries.length == 0) return (Table_t){};
Table_t t = {};
int64_t length = entries.length + entries.length / 4;
@@ -619,19 +574,19 @@ public Table_t Table$from_entries(List_t entries, const TypeInfo_t *type)
t.bucket_info = GC_MALLOC_ATOMIC(alloc_size);
memset(t.bucket_info->buckets, 0, sizeof(bucket_t[length]));
t.bucket_info->count = length;
- t.bucket_info->last_free = length-1;
+ t.bucket_info->last_free = length - 1;
size_t offset = value_offset(type);
for (int64_t i = 0; i < entries.length; i++) {
- void *key = entries.data + i*entries.stride;
+ void *key = entries.data + i * entries.stride;
Table$set(&t, key, key + offset, type);
}
return t;
}
// Overlap is "set intersection" in formal terms
-public Table_t Table$overlap(Table_t a, Table_t b, const TypeInfo_t *type)
-{
+public
+Table_t Table$overlap(Table_t a, Table_t b, const TypeInfo_t *type) {
// Return a table such that t[k]==a[k] for all k such that a.has(k), b.has(k), and a[k]==b[k]
Table_t result = {};
const size_t offset = value_offset(type);
@@ -648,9 +603,10 @@ public Table_t Table$overlap(Table_t a, Table_t b, const TypeInfo_t *type)
}
// With is "set union" in formal terms
-public Table_t Table$with(Table_t a, Table_t b, const TypeInfo_t *type)
-{
- // return a table such that t[k]==b[k] for all k such that b.has(k), and t[k]==a[k] for all k such that a.has(k) and not b.has(k)
+public
+Table_t Table$with(Table_t a, Table_t b, const TypeInfo_t *type) {
+ // return a table such that t[k]==b[k] for all k such that b.has(k), and t[k]==a[k] for all k such that a.has(k) and
+ // not b.has(k)
Table_t result = {};
const size_t offset = value_offset(type);
for (Table_t *t = &a; t; t = t->fallback) {
@@ -669,31 +625,29 @@ public Table_t Table$with(Table_t a, Table_t b, const TypeInfo_t *type)
}
// Xor is "disjunctive union" or "symmetric difference" in formal terms
-public Table_t Table$xor(Table_t a, Table_t b, const TypeInfo_t *type)
-{
+public
+Table_t Table$xor(Table_t a, Table_t b, const TypeInfo_t *type) {
// return a table with elements in `a` or `b`, but not both
Table_t result = {};
const size_t offset = value_offset(type);
for (Table_t *t = &a; t; t = t->fallback) {
for (int64_t i = 0; i < Table$length(*t); i++) {
void *key = GET_ENTRY(*t, i);
- if (Table$get(b, key, type) == NULL)
- Table$set(&result, key, key + offset, type);
+ if (Table$get(b, key, type) == NULL) Table$set(&result, key, key + offset, type);
}
}
for (Table_t *t = &b; t; t = t->fallback) {
for (int64_t i = 0; i < Table$length(*t); i++) {
void *key = GET_ENTRY(*t, i);
- if (Table$get(a, key, type) == NULL)
- Table$set(&result, key, key + offset, type);
+ if (Table$get(a, key, type) == NULL) Table$set(&result, key, key + offset, type);
}
}
return result;
}
// Without is "set difference" in formal terms
-public Table_t Table$without(Table_t a, Table_t b, const TypeInfo_t *type)
-{
+public
+Table_t Table$without(Table_t a, Table_t b, const TypeInfo_t *type) {
// Return a table such that t[k]==a[k] for all k such that not b.has(k) or b[k] != a[k]
Table_t result = {};
const size_t offset = value_offset(type);
@@ -709,8 +663,8 @@ public Table_t Table$without(Table_t a, Table_t b, const TypeInfo_t *type)
return result;
}
-public Table_t Table$with_fallback(Table_t t, OptionalTable_t fallback)
-{
+public
+Table_t Table$with_fallback(Table_t t, OptionalTable_t fallback) {
if (fallback.entries.length <= 0) {
t.fallback = NULL;
return t;
@@ -722,10 +676,8 @@ public Table_t Table$with_fallback(Table_t t, OptionalTable_t fallback)
}
}
-PUREFUNC public bool Table$is_subset_of(Table_t a, Table_t b, bool strict, const TypeInfo_t *type)
-{
- if (a.entries.length > b.entries.length || (strict && a.entries.length == b.entries.length))
- return false;
+PUREFUNC public bool Table$is_subset_of(Table_t a, Table_t b, bool strict, const TypeInfo_t *type) {
+ if (a.entries.length > b.entries.length || (strict && a.entries.length == b.entries.length)) return false;
for (int64_t i = 0; i < Table$length(a); i++) {
void *found = Table$get_raw(b, GET_ENTRY(a, i), type);
@@ -734,73 +686,61 @@ PUREFUNC public bool Table$is_subset_of(Table_t a, Table_t b, bool strict, const
return true;
}
-PUREFUNC public bool Table$is_superset_of(Table_t a, Table_t b, bool strict, const TypeInfo_t *type)
-{
+PUREFUNC public bool Table$is_superset_of(Table_t a, Table_t b, bool strict, const TypeInfo_t *type) {
return Table$is_subset_of(b, a, strict, type);
}
-PUREFUNC public void *Table$str_get(Table_t t, const char *key)
-{
+PUREFUNC public void *Table$str_get(Table_t t, const char *key) {
void **ret = Table$get(t, &key, &CStrToVoidStarTable);
return ret ? *ret : NULL;
}
-PUREFUNC public void *Table$str_get_raw(Table_t t, const char *key)
-{
+PUREFUNC public void *Table$str_get_raw(Table_t t, const char *key) {
void **ret = Table$get_raw(t, &key, &CStrToVoidStarTable);
return ret ? *ret : NULL;
}
-public void *Table$str_reserve(Table_t *t, const char *key, const void *value)
-{
+public
+void *Table$str_reserve(Table_t *t, const char *key, const void *value) {
return Table$reserve(t, &key, &value, &CStrToVoidStarTable);
}
-public void Table$str_set(Table_t *t, const char *key, const void *value)
-{
- Table$set(t, &key, &value, &CStrToVoidStarTable);
-}
+public
+void Table$str_set(Table_t *t, const char *key, const void *value) { Table$set(t, &key, &value, &CStrToVoidStarTable); }
-public void Table$str_remove(Table_t *t, const char *key)
-{
- return Table$remove(t, &key, &CStrToVoidStarTable);
-}
+public
+void Table$str_remove(Table_t *t, const char *key) { return Table$remove(t, &key, &CStrToVoidStarTable); }
-CONSTFUNC public void *Table$str_entry(Table_t t, int64_t n)
-{
- return Table$entry(t, n);
-}
+CONSTFUNC public void *Table$str_entry(Table_t t, int64_t n) { return Table$entry(t, n); }
-PUREFUNC public bool Table$is_none(const void *obj, const TypeInfo_t *info)
-{
+PUREFUNC public bool Table$is_none(const void *obj, const TypeInfo_t *info) {
(void)info;
- return ((Table_t*)obj)->entries.length < 0;
+ return ((Table_t *)obj)->entries.length < 0;
}
-public void Table$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type)
-{
- Table_t *t = (Table_t*)obj;
+public
+void Table$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *type) {
+ Table_t *t = (Table_t *)obj;
int64_t len = t->entries.length;
Int64$serialize(&len, out, pointers, &Int64$info);
size_t offset = value_offset(type);
for (int64_t i = 0; i < len; i++) {
- _serialize(t->entries.data + i*t->entries.stride, out, pointers, type->TableInfo.key);
+ _serialize(t->entries.data + i * t->entries.stride, out, pointers, type->TableInfo.key);
if (type->TableInfo.value->size > 0)
- _serialize(t->entries.data + i*t->entries.stride + offset, out, pointers, type->TableInfo.value);
+ _serialize(t->entries.data + i * t->entries.stride + offset, out, pointers, type->TableInfo.value);
}
assert(fputc(t->fallback != NULL ? 1 : 0, out) != EOF);
- if (t->fallback)
- Table$serialize(t->fallback, out, pointers, type);
+ if (t->fallback) Table$serialize(t->fallback, out, pointers, type);
}
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstack-protector"
#endif
-public void Table$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *type)
-{
+public
+void Table$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_t *type) {
int64_t len;
Int64$deserialize(in, &len, pointers, &Int$info);
@@ -809,8 +749,7 @@ public void Table$deserialize(FILE *in, void *outval, List_t *pointers, const Ty
char key[type->TableInfo.key->size];
_deserialize(in, key, pointers, type->TableInfo.key);
char value[type->TableInfo.value->size];
- if (type->TableInfo.value->size > 0)
- _deserialize(in, value, pointers, type->TableInfo.value);
+ if (type->TableInfo.value->size > 0) _deserialize(in, value, pointers, type->TableInfo.value);
Table$set(&t, key, value, type);
}
@@ -819,7 +758,7 @@ public void Table$deserialize(FILE *in, void *outval, List_t *pointers, const Ty
Table$deserialize(in, t.fallback, pointers, type);
}
- *(Table_t*)outval = t;
+ *(Table_t *)outval = t;
}
#ifdef __GNUC__
#pragma GCC diagnostic pop
diff --git a/src/stdlib/tables.h b/src/stdlib/tables.h
index f80c16c3..65f35060 100644
--- a/src/stdlib/tables.h
+++ b/src/stdlib/tables.h
@@ -2,59 +2,94 @@
// Hash table datastructure with methods and type information
-#include <stdint.h>
#include <stdbool.h>
+#include <stdint.h>
#include <string.h>
-#include "lists.h"
#include "datatypes.h"
+#include "lists.h"
#include "types.h"
#include "util.h"
-#define Table(key_t, val_t, key_info, value_info, fb, N, ...) ({ \
- struct { key_t k; val_t v; } ents[N] = {__VA_ARGS__}; \
- Table_t table = Table$from_entries((List_t){ \
- .data=memcpy(GC_MALLOC(sizeof(ents)), ents, sizeof(ents)), \
- .length=sizeof(ents)/sizeof(ents[0]), \
- .stride=(void*)&ents[1] - (void*)&ents[0], \
- }, Table$info(key_info, value_info)); \
- table.fallback = fb; \
- table; })
-#define Set(item_t, item_info, N, ...) ({ \
- item_t ents[N] = {__VA_ARGS__}; \
- Table_t set = Table$from_entries((List_t){ \
- .data=memcpy(GC_MALLOC(sizeof(ents)), ents, sizeof(ents)), \
- .length=sizeof(ents)/sizeof(ents[0]), \
- .stride=(void*)&ents[1] - (void*)&ents[0], \
- }, Set$info(item_info)); \
- set; })
+#define Table(key_t, val_t, key_info, value_info, fb, N, ...) \
+ ({ \
+ struct { \
+ key_t k; \
+ val_t v; \
+ } ents[N] = {__VA_ARGS__}; \
+ Table_t table = Table$from_entries( \
+ (List_t){ \
+ .data = memcpy(GC_MALLOC(sizeof(ents)), ents, sizeof(ents)), \
+ .length = sizeof(ents) / sizeof(ents[0]), \
+ .stride = (void *)&ents[1] - (void *)&ents[0], \
+ }, \
+ Table$info(key_info, value_info)); \
+ table.fallback = fb; \
+ table; \
+ })
+#define Set(item_t, item_info, N, ...) \
+ ({ \
+ item_t ents[N] = {__VA_ARGS__}; \
+ Table_t set = Table$from_entries( \
+ (List_t){ \
+ .data = memcpy(GC_MALLOC(sizeof(ents)), ents, sizeof(ents)), \
+ .length = sizeof(ents) / sizeof(ents[0]), \
+ .stride = (void *)&ents[1] - (void *)&ents[0], \
+ }, \
+ Set$info(item_info)); \
+ set; \
+ })
Table_t Table$from_entries(List_t entries, const TypeInfo_t *type);
void *Table$get(Table_t t, const void *key, const TypeInfo_t *type);
-#define Table$get_optional(table_expr, key_t, val_t, key_expr, nonnull_var, nonnull_expr, null_expr, info_expr) ({ \
- const Table_t t = table_expr; const key_t k = key_expr; \
- val_t *nonnull_var = Table$get(t, &k, info_expr); \
- nonnull_var ? nonnull_expr : null_expr; })
-#define Table$get_or_setdefault(table_expr, key_t, val_t, key_expr, default_expr, info_expr) ({ \
- Table_t *t = table_expr; const key_t k = key_expr; \
- if (t->entries.data_refcount > 0) List$compact(&t->entries, sizeof(struct {key_t k; val_t v;})); \
- val_t *v = Table$get(*t, &k, info_expr); \
- v ? v : (val_t*)Table$reserve(t, &k, (val_t[1]){default_expr}, info_expr); })
-#define Table$get_or_default(table_expr, key_t, val_t, key_expr, default_expr, info_expr) ({ \
- const Table_t t = table_expr; const key_t k = key_expr; \
- val_t *v = Table$get(t, &k, info_expr); \
- v ? *v : default_expr; })
-#define Table$has_value(table_expr, key_expr, info_expr) ({ \
- const Table_t t = table_expr; __typeof(key_expr) k = key_expr; \
- (Table$get(t, &k, info_expr) != NULL); })
+#define Table$get_optional(table_expr, key_t, val_t, key_expr, nonnull_var, nonnull_expr, null_expr, info_expr) \
+ ({ \
+ const Table_t t = table_expr; \
+ const key_t k = key_expr; \
+ val_t *nonnull_var = Table$get(t, &k, info_expr); \
+ nonnull_var ? nonnull_expr : null_expr; \
+ })
+#define Table$get_or_setdefault(table_expr, key_t, val_t, key_expr, default_expr, info_expr) \
+ ({ \
+ Table_t *t = table_expr; \
+ const key_t k = key_expr; \
+ if (t->entries.data_refcount > 0) \
+ List$compact(&t->entries, sizeof(struct { \
+ key_t k; \
+ val_t v; \
+ })); \
+ val_t *v = Table$get(*t, &k, info_expr); \
+ v ? v : (val_t *)Table$reserve(t, &k, (val_t[1]){default_expr}, info_expr); \
+ })
+#define Table$get_or_default(table_expr, key_t, val_t, key_expr, default_expr, info_expr) \
+ ({ \
+ const Table_t t = table_expr; \
+ const key_t k = key_expr; \
+ val_t *v = Table$get(t, &k, info_expr); \
+ v ? *v : default_expr; \
+ })
+#define Table$has_value(table_expr, key_expr, info_expr) \
+ ({ \
+ const Table_t t = table_expr; \
+ __typeof(key_expr) k = key_expr; \
+ (Table$get(t, &k, info_expr) != NULL); \
+ })
PUREFUNC void *Table$get_raw(Table_t t, const void *key, const TypeInfo_t *type);
CONSTFUNC void *Table$entry(Table_t t, int64_t n);
void *Table$reserve(Table_t *t, const void *key, const void *value, const TypeInfo_t *type);
void Table$set(Table_t *t, const void *key, const void *value, const TypeInfo_t *type);
-#define Table$set_value(t, key_expr, value_expr, type) ({ __typeof(key_expr) k = key_expr; __typeof(value_expr) v = value_expr; \
- Table$set(t, &k, &v, type); })
+#define Table$set_value(t, key_expr, value_expr, type) \
+ ({ \
+ __typeof(key_expr) k = key_expr; \
+ __typeof(value_expr) v = value_expr; \
+ Table$set(t, &k, &v, type); \
+ })
void Table$remove(Table_t *t, const void *key, const TypeInfo_t *type);
-#define Table$remove_value(t, key_expr, type) ({ __typeof(key_expr) k = key_expr; Table$remove(t, &k, type); })
+#define Table$remove_value(t, key_expr, type) \
+ ({ \
+ __typeof(key_expr) k = key_expr; \
+ Table$remove(t, &k, type); \
+ })
Table_t Table$overlap(Table_t a, Table_t b, const TypeInfo_t *type);
Table_t Table$with(Table_t a, Table_t b, const TypeInfo_t *type);
@@ -67,13 +102,22 @@ PUREFUNC bool Table$is_superset_of(Table_t a, Table_t b, bool strict, const Type
void Table$clear(Table_t *t);
Table_t Table$sorted(Table_t t, const TypeInfo_t *type);
void Table$mark_copy_on_write(Table_t *t);
-#define TABLE_INCREF(t) ({ LIST_INCREF((t).entries); if ((t).bucket_info) (t).bucket_info->data_refcount += ((t).bucket_info->data_refcount < TABLE_MAX_DATA_REFCOUNT); })
-#define TABLE_COPY(t) ({ TABLE_INCREF(t); t; })
+#define TABLE_INCREF(t) \
+ ({ \
+ LIST_INCREF((t).entries); \
+ if ((t).bucket_info) \
+ (t).bucket_info->data_refcount += ((t).bucket_info->data_refcount < TABLE_MAX_DATA_REFCOUNT); \
+ })
+#define TABLE_COPY(t) \
+ ({ \
+ TABLE_INCREF(t); \
+ t; \
+ })
PUREFUNC int32_t Table$compare(const void *x, const void *y, const TypeInfo_t *type);
PUREFUNC bool Table$equal(const void *x, const void *y, const TypeInfo_t *type);
PUREFUNC uint64_t Table$hash(const void *t, const TypeInfo_t *type);
Text_t Table$as_text(const void *t, bool colorize, const TypeInfo_t *type);
-PUREFUNC bool Table$is_none(const void *obj, const TypeInfo_t*);
+PUREFUNC bool Table$is_none(const void *obj, const TypeInfo_t *);
CONSTFUNC void *Table$str_entry(Table_t t, int64_t n);
PUREFUNC void *Table$str_get(Table_t t, const char *key);
@@ -88,19 +132,30 @@ void Table$deserialize(FILE *in, void *outval, List_t *pointers, const TypeInfo_
extern const TypeInfo_t CStrToVoidStarTable;
-#define Table$metamethods { \
- .as_text=Table$as_text, \
- .compare=Table$compare, \
- .equal=Table$equal, \
- .hash=Table$hash, \
- .is_none=Table$is_none, \
- .serialize=Table$serialize, \
- .deserialize=Table$deserialize, \
-}
+#define Table$metamethods \
+ { \
+ .as_text = Table$as_text, \
+ .compare = Table$compare, \
+ .equal = Table$equal, \
+ .hash = Table$hash, \
+ .is_none = Table$is_none, \
+ .serialize = Table$serialize, \
+ .deserialize = Table$deserialize, \
+ }
-#define Table$info(key_expr, value_expr) &((TypeInfo_t){.size=sizeof(Table_t), .align=__alignof__(Table_t), \
- .tag=TableInfo, .TableInfo.key=key_expr, .TableInfo.value=value_expr, .metamethods=Table$metamethods})
-#define Set$info(item_info) &((TypeInfo_t){.size=sizeof(Table_t), .align=__alignof__(Table_t), \
- .tag=TableInfo, .TableInfo.key=item_info, .TableInfo.value=&Void$info, .metamethods=Table$metamethods})
+#define Table$info(key_expr, value_expr) \
+ &((TypeInfo_t){.size = sizeof(Table_t), \
+ .align = __alignof__(Table_t), \
+ .tag = TableInfo, \
+ .TableInfo.key = key_expr, \
+ .TableInfo.value = value_expr, \
+ .metamethods = Table$metamethods})
+#define Set$info(item_info) \
+ &((TypeInfo_t){.size = sizeof(Table_t), \
+ .align = __alignof__(Table_t), \
+ .tag = TableInfo, \
+ .TableInfo.key = item_info, \
+ .TableInfo.value = &Void$info, \
+ .metamethods = Table$metamethods})
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1
diff --git a/src/stdlib/text.c b/src/stdlib/text.c
index d9793eb8..aad3fd76 100644
--- a/src/stdlib/text.c
+++ b/src/stdlib/text.c
@@ -116,8 +116,8 @@
#include "text.h"
// Use inline version of the siphash code for performance:
-#include "siphash.h"
#include "siphash-internals.h"
+#include "siphash.h"
typedef struct {
ucs4_t main_codepoint;
@@ -133,9 +133,9 @@ static synthetic_grapheme_t *synthetic_graphemes = NULL;
static int32_t synthetic_grapheme_capacity = 0;
static int32_t num_synthetic_graphemes = 0;
-#define NUM_GRAPHEME_CODEPOINTS(id) (synthetic_graphemes[-(id)-1].utf32_cluster[0])
-#define GRAPHEME_CODEPOINTS(id) (&synthetic_graphemes[-(id)-1].utf32_cluster[1])
-#define GRAPHEME_UTF8(id) (synthetic_graphemes[-(id)-1].utf8)
+#define NUM_GRAPHEME_CODEPOINTS(id) (synthetic_graphemes[-(id) - 1].utf32_cluster[0])
+#define GRAPHEME_CODEPOINTS(id) (&synthetic_graphemes[-(id) - 1].utf32_cluster[1])
+#define GRAPHEME_UTF8(id) (synthetic_graphemes[-(id) - 1].utf8)
// Somewhat arbitrarily chosen, if two short literal ASCII or grapheme chunks
// are concatenated below this length threshold, we just merge them into a
@@ -145,16 +145,17 @@ static int32_t num_synthetic_graphemes = 0;
static Text_t simple_concatenation(Text_t a, Text_t b);
-public Text_t EMPTY_TEXT = {
- .length=0,
- .tag=TEXT_ASCII,
- .ascii=0,
+public
+Text_t EMPTY_TEXT = {
+ .length = 0,
+ .tag = TEXT_ASCII,
+ .ascii = 0,
};
PUREFUNC static bool graphemes_equal(const void *va, const void *vb, const TypeInfo_t *info) {
(void)info;
- ucs4_t *a = *(ucs4_t**)va;
- ucs4_t *b = *(ucs4_t**)vb;
+ ucs4_t *a = *(ucs4_t **)va;
+ ucs4_t *b = *(ucs4_t **)vb;
if (a[0] != b[0]) return false;
for (int i = 0; i < (int)a[0]; i++)
if (a[i] != b[i]) return false;
@@ -163,37 +164,37 @@ PUREFUNC static bool graphemes_equal(const void *va, const void *vb, const TypeI
PUREFUNC static uint64_t grapheme_hash(const void *g, const TypeInfo_t *info) {
(void)info;
- ucs4_t *cluster = *(ucs4_t**)g;
- return siphash24((void*)&cluster[1], sizeof(ucs4_t[cluster[0]]));
+ ucs4_t *cluster = *(ucs4_t **)g;
+ return siphash24((void *)&cluster[1], sizeof(ucs4_t[cluster[0]]));
}
static const TypeInfo_t GraphemeClusterInfo = {
- .size=sizeof(ucs4_t*),
- .align=__alignof__(ucs4_t*),
- .metamethods={
- .equal=graphemes_equal,
- .hash=grapheme_hash,
- },
+ .size = sizeof(ucs4_t *),
+ .align = __alignof__(ucs4_t *),
+ .metamethods =
+ {
+ .equal = graphemes_equal,
+ .hash = grapheme_hash,
+ },
};
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstack-protector"
#endif
-public int32_t get_synthetic_grapheme(const ucs4_t *codepoints, int64_t utf32_len)
-{
- if (utf32_len == 1)
- return (int32_t)*codepoints;
+public
+int32_t get_synthetic_grapheme(const ucs4_t *codepoints, int64_t utf32_len) {
+ if (utf32_len == 1) return (int32_t)*codepoints;
- ucs4_t length_prefixed[1+utf32_len];
+ ucs4_t length_prefixed[1 + utf32_len];
length_prefixed[0] = (ucs4_t)utf32_len;
for (int i = 0; i < utf32_len; i++)
- length_prefixed[i+1] = codepoints[i];
+ length_prefixed[i + 1] = codepoints[i];
ucs4_t *ptr = &length_prefixed[0];
// Optimization for common case of one frequently used synthetic grapheme:
static int32_t last_grapheme = 0;
- if (last_grapheme != 0 && graphemes_equal(&ptr, &synthetic_graphemes[-last_grapheme-1].utf32_cluster, NULL))
+ if (last_grapheme != 0 && graphemes_equal(&ptr, &synthetic_graphemes[-last_grapheme - 1].utf32_cluster, NULL))
return last_grapheme;
TypeInfo_t GraphemeIDLookupTableInfo = *Table$info(&GraphemeClusterInfo, &Int32$info);
@@ -209,12 +210,12 @@ public int32_t get_synthetic_grapheme(const ucs4_t *codepoints, int64_t utf32_le
synthetic_graphemes = new;
}
- int32_t grapheme_id = -(num_synthetic_graphemes+1);
+ int32_t grapheme_id = -(num_synthetic_graphemes + 1);
num_synthetic_graphemes += 1;
// Get UTF8 representation:
uint8_t u8_buf[64];
- size_t u8_len = sizeof(u8_buf)/sizeof(u8_buf[0]);
+ size_t u8_len = sizeof(u8_buf) / sizeof(u8_buf[0]);
uint8_t *u8 = u32_to_u8(codepoints, (size_t)utf32_len, u8_buf, &u8_len);
if (u8 == NULL) fail("Invalid graphemes encountered!");
@@ -223,11 +224,10 @@ public int32_t get_synthetic_grapheme(const ucs4_t *codepoints, int64_t utf32_le
// area with good cache locality:
static void *arena = NULL, *arena_end = NULL;
// Eat up any space needed to make arena 32-bit aligned:
- if ((size_t)arena % __alignof__(ucs4_t) != 0)
- arena += __alignof__(ucs4_t) - ((size_t)arena % __alignof__(ucs4_t));
+ if ((size_t)arena % __alignof__(ucs4_t) != 0) arena += __alignof__(ucs4_t) - ((size_t)arena % __alignof__(ucs4_t));
// If we have filled up this arena, allocate a new one:
- size_t needed_memory = sizeof(ucs4_t[1+utf32_len]) + sizeof(uint8_t[u8_len + 1]);
+ size_t needed_memory = sizeof(ucs4_t[1 + utf32_len]) + sizeof(uint8_t[u8_len + 1]);
if (arena + needed_memory > arena_end) {
// Do reasonably big chunks at a time, so most synthetic codepoints are
// nearby each other in memory and cache locality is good. This is a
@@ -239,28 +239,27 @@ public int32_t get_synthetic_grapheme(const ucs4_t *codepoints, int64_t utf32_le
// Copy length-prefixed UTF32 codepoints into the arena and store where they live:
ucs4_t *codepoint_copy = arena;
- memcpy(codepoint_copy, length_prefixed, sizeof(ucs4_t[1+utf32_len]));
- synthetic_graphemes[-grapheme_id-1].utf32_cluster = codepoint_copy;
- arena += sizeof(ucs4_t[1+utf32_len]);
+ memcpy(codepoint_copy, length_prefixed, sizeof(ucs4_t[1 + utf32_len]));
+ synthetic_graphemes[-grapheme_id - 1].utf32_cluster = codepoint_copy;
+ arena += sizeof(ucs4_t[1 + utf32_len]);
// Copy UTF8 bytes into the arena and store where they live:
uint8_t *utf8_final = arena;
memcpy(utf8_final, u8, sizeof(uint8_t[u8_len]));
utf8_final[u8_len] = '\0'; // Add a terminating NUL byte
- synthetic_graphemes[-grapheme_id-1].utf8 = utf8_final;
+ synthetic_graphemes[-grapheme_id - 1].utf8 = utf8_final;
arena += sizeof(uint8_t[u8_len + 1]);
// Sickos at the unicode consortium decreed that you can have grapheme clusters
// that begin with *prefix* modifiers, so we gotta check for that case:
- synthetic_graphemes[-grapheme_id-1].main_codepoint = length_prefixed[1];
+ synthetic_graphemes[-grapheme_id - 1].main_codepoint = length_prefixed[1];
for (ucs4_t i = 0; i < utf32_len; i++) {
#if _LIBUNISTRING_VERSION >= 0x010200
-// libuinstring version 1.2.0 introduced uc_is_property_prepended_concatenation_mark()
-// It's not critical, but it's technically more correct to have this check:
- if (unlikely(uc_is_property_prepended_concatenation_mark(length_prefixed[1+i])))
- continue;
+ // libuinstring version 1.2.0 introduced uc_is_property_prepended_concatenation_mark()
+ // It's not critical, but it's technically more correct to have this check:
+ if (unlikely(uc_is_property_prepended_concatenation_mark(length_prefixed[1 + i]))) continue;
#endif
- synthetic_graphemes[-grapheme_id-1].main_codepoint = length_prefixed[1+i];
+ synthetic_graphemes[-grapheme_id - 1].main_codepoint = length_prefixed[1 + i];
break;
}
@@ -276,8 +275,8 @@ public int32_t get_synthetic_grapheme(const ucs4_t *codepoints, int64_t utf32_le
#pragma GCC diagnostic pop
#endif
-public int Text$print(FILE *stream, Text_t t)
-{
+public
+int Text$print(FILE *stream, Text_t t) {
if (t.length == 0) return 0;
switch (t.tag) {
@@ -290,14 +289,14 @@ public int Text$print(FILE *stream, Text_t t)
if (grapheme >= 0) {
uint8_t buf[8];
size_t len = sizeof(buf);
- uint8_t *u8 = u32_to_u8((ucs4_t*)&grapheme, 1, buf, &len);
+ uint8_t *u8 = u32_to_u8((ucs4_t *)&grapheme, 1, buf, &len);
if (u8 == NULL) fail("Invalid grapheme encountered: ", grapheme);
written += (int)fwrite(u8, sizeof(char), len, stream);
if (u8 != buf) free(u8);
} else {
const uint8_t *u8 = GRAPHEME_UTF8(grapheme);
assert(u8);
- written += (int)fwrite(u8, sizeof(uint8_t), strlen((char*)u8), stream);
+ written += (int)fwrite(u8, sizeof(uint8_t), strlen((char *)u8), stream);
}
}
return written;
@@ -309,14 +308,14 @@ public int Text$print(FILE *stream, Text_t t)
if (grapheme >= 0) {
uint8_t buf[8];
size_t len = sizeof(buf);
- uint8_t *u8 = u32_to_u8((ucs4_t*)&grapheme, 1, buf, &len);
+ uint8_t *u8 = u32_to_u8((ucs4_t *)&grapheme, 1, buf, &len);
if (u8 == NULL) fail("Invalid grapheme encountered: ", grapheme);
written += (int)fwrite(u8, sizeof(char), len, stream);
if (u8 != buf) free(u8);
} else {
const uint8_t *u8 = GRAPHEME_UTF8(grapheme);
assert(u8);
- written += (int)fwrite(u8, sizeof(uint8_t), strlen((char*)u8), stream);
+ written += (int)fwrite(u8, sizeof(uint8_t), strlen((char *)u8), stream);
}
}
return written;
@@ -332,16 +331,16 @@ public int Text$print(FILE *stream, Text_t t)
static const int64_t min_len_for_depth[MAX_TEXT_DEPTH] = {
// Fibonacci numbers (skipping first two)
- 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946,
- 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578,
- 5702887, 9227465, 14930352, 24157817, 39088169, 63245986, 102334155, 165580141, 267914296,
- 433494437, 701408733, 1134903170, 1836311903, 2971215073, 4807526976, 7778742049,
+ 1, 2, 3, 5, 8, 13, 21, 34, 55, 89,
+ 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946,
+ 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269,
+ 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986, 102334155, 165580141,
+ 267914296, 433494437, 701408733, 1134903170, 1836311903, 2971215073, 4807526976, 7778742049,
};
#define IS_BALANCED_TEXT(t) ((t).length >= min_len_for_depth[(t).depth])
-static void insert_balanced_recursive(Text_t balanced_texts[MAX_TEXT_DEPTH], Text_t text)
-{
+static void insert_balanced_recursive(Text_t balanced_texts[MAX_TEXT_DEPTH], Text_t text) {
if (text.tag == TEXT_CONCAT && (!IS_BALANCED_TEXT(text) || text.depth >= MAX_TEXT_DEPTH)) {
insert_balanced_recursive(balanced_texts, *text.left);
insert_balanced_recursive(balanced_texts, *text.right);
@@ -370,8 +369,7 @@ static void insert_balanced_recursive(Text_t balanced_texts[MAX_TEXT_DEPTH], Tex
balanced_texts[i] = accumulator;
}
-static Text_t rebalanced(Text_t a, Text_t b)
-{
+static Text_t rebalanced(Text_t a, Text_t b) {
Text_t balanced_texts[MAX_TEXT_DEPTH];
memset(balanced_texts, 0, sizeof(balanced_texts));
insert_balanced_recursive(balanced_texts, a);
@@ -379,14 +377,12 @@ static Text_t rebalanced(Text_t a, Text_t b)
Text_t ret = EMPTY_TEXT;
for (int i = 0; ret.length < a.length + b.length; i++) {
- if (balanced_texts[i].length)
- ret = simple_concatenation(balanced_texts[i], ret);
+ if (balanced_texts[i].length) ret = simple_concatenation(balanced_texts[i], ret);
}
return ret;
}
-Text_t simple_concatenation(Text_t a, Text_t b)
-{
+Text_t simple_concatenation(Text_t a, Text_t b) {
if (a.length == 0) return b;
if (b.length == 0) return a;
@@ -395,53 +391,53 @@ Text_t simple_concatenation(Text_t a, Text_t b)
// every concatenation to yield a balanced text, since many concatenations
// are ephemeral (e.g. doing a loop repeatedly concatenating without using
// the intermediary values).
- if (new_depth >= MAX_TEXT_DEPTH)
- return rebalanced(a, b);
+ if (new_depth >= MAX_TEXT_DEPTH) return rebalanced(a, b);
Text_t *children = GC_MALLOC(sizeof(Text_t[2]));
children[0] = a;
children[1] = b;
return (Text_t){
- .tag=TEXT_CONCAT,
- .length=a.length + b.length,
- .depth=new_depth,
- .left=&children[0],
- .right=&children[1],
+ .tag = TEXT_CONCAT,
+ .length = a.length + b.length,
+ .depth = new_depth,
+ .left = &children[0],
+ .right = &children[1],
};
}
-static Text_t concat2_assuming_safe(Text_t a, Text_t b)
-{
+static Text_t concat2_assuming_safe(Text_t a, Text_t b) {
if (a.length == 0) return b;
if (b.length == 0) return a;
if (a.tag == TEXT_ASCII && b.tag == TEXT_ASCII && (size_t)(a.length + b.length) <= SHORT_ASCII_LENGTH) {
struct Text_s ret = {
- .tag=TEXT_ASCII,
- .length=a.length + b.length,
+ .tag = TEXT_ASCII,
+ .length = a.length + b.length,
};
ret.ascii = GC_MALLOC_ATOMIC(sizeof(char[ret.length]));
- memcpy((char*)ret.ascii, a.ascii, sizeof(char[a.length]));
- memcpy((char*)&ret.ascii[a.length], b.ascii, sizeof(char[b.length]));
+ memcpy((char *)ret.ascii, a.ascii, sizeof(char[a.length]));
+ memcpy((char *)&ret.ascii[a.length], b.ascii, sizeof(char[b.length]));
return ret;
- } else if (a.tag == TEXT_GRAPHEMES && b.tag == TEXT_GRAPHEMES && (size_t)(a.length + b.length) <= SHORT_GRAPHEMES_LENGTH) {
+ } else if (a.tag == TEXT_GRAPHEMES && b.tag == TEXT_GRAPHEMES
+ && (size_t)(a.length + b.length) <= SHORT_GRAPHEMES_LENGTH) {
struct Text_s ret = {
- .tag=TEXT_GRAPHEMES,
- .length=a.length + b.length,
+ .tag = TEXT_GRAPHEMES,
+ .length = a.length + b.length,
};
ret.graphemes = GC_MALLOC_ATOMIC(sizeof(int32_t[ret.length]));
- memcpy((int32_t*)ret.graphemes, a.graphemes, sizeof(int32_t[a.length]));
- memcpy((int32_t*)&ret.graphemes[a.length], b.graphemes, sizeof(int32_t[b.length]));
+ memcpy((int32_t *)ret.graphemes, a.graphemes, sizeof(int32_t[a.length]));
+ memcpy((int32_t *)&ret.graphemes[a.length], b.graphemes, sizeof(int32_t[b.length]));
return ret;
- } else if (a.tag != TEXT_CONCAT && b.tag != TEXT_CONCAT && (size_t)(a.length + b.length) <= SHORT_GRAPHEMES_LENGTH) {
+ } else if (a.tag != TEXT_CONCAT && b.tag != TEXT_CONCAT
+ && (size_t)(a.length + b.length) <= SHORT_GRAPHEMES_LENGTH) {
// Turn a small bit of ASCII into graphemes if it helps make things smaller
// Text structs come with an extra 8 bytes, so allocate enough to hold the text
struct Text_s ret = {
- .tag=TEXT_GRAPHEMES,
- .length=a.length + b.length,
+ .tag = TEXT_GRAPHEMES,
+ .length = a.length + b.length,
};
ret.graphemes = GC_MALLOC_ATOMIC(sizeof(int32_t[ret.length]));
- int32_t *dest = (int32_t*)ret.graphemes;
+ int32_t *dest = (int32_t *)ret.graphemes;
if (a.tag == TEXT_GRAPHEMES) {
memcpy(dest, a.graphemes, sizeof(int32_t[a.length]));
dest += a.length;
@@ -474,12 +470,11 @@ static Text_t concat2_assuming_safe(Text_t a, Text_t b)
return simple_concatenation(a, b);
}
-static Text_t concat2(Text_t a, Text_t b)
-{
+static Text_t concat2(Text_t a, Text_t b) {
if (a.length == 0) return b;
if (b.length == 0) return a;
- int32_t last_a = Text$get_grapheme(a, a.length-1);
+ int32_t last_a = Text$get_grapheme(a, a.length - 1);
int32_t first_b = Text$get_grapheme(b, 0);
// Magic number, we know that no codepoints below here trigger instability:
@@ -509,60 +504,51 @@ static Text_t concat2(Text_t a, Text_t b)
// Do a normalization run for these two codepoints and see if it looks different.
// Normalization should not exceed 3x in the input length (but if it does, it will be
// handled gracefully)
- ucs4_t norm_buf[3*len];
- size_t norm_length = sizeof(norm_buf)/sizeof(norm_buf[0]);
+ ucs4_t norm_buf[3 * len];
+ size_t norm_length = sizeof(norm_buf) / sizeof(norm_buf[0]);
ucs4_t *normalized = u32_normalize(UNINORM_NFC, codepoints, len, norm_buf, &norm_length);
bool stable = (norm_length == len && memcmp(codepoints, normalized, sizeof(codepoints)) == 0);
if (stable) {
const void *second_grapheme = u32_grapheme_next(normalized, &normalized[norm_length]);
- if (second_grapheme == &normalized[norm_length])
- stable = false;
+ if (second_grapheme == &normalized[norm_length]) stable = false;
}
if likely (stable) {
- if (normalized != norm_buf)
- free(normalized);
+ if (normalized != norm_buf) free(normalized);
return concat2_assuming_safe(a, b);
}
- Text_t glue = Text$from_codepoints((List_t){.data=norm_buf, .length=(int64_t)norm_length, .stride=sizeof(int32_t)});
+ Text_t glue =
+ Text$from_codepoints((List_t){.data = norm_buf, .length = (int64_t)norm_length, .stride = sizeof(int32_t)});
- if (normalized != norm_buf)
- free(normalized);
+ if (normalized != norm_buf) free(normalized);
- if (a.length == 1 && b.length == 1)
- return glue;
- else if (a.length == 1)
- return concat2_assuming_safe(glue, Text$slice(b, I(2), I(b.length)));
- else if (b.length == 1)
- return concat2_assuming_safe(Text$slice(a, I(1), I(a.length-1)), glue);
+ if (a.length == 1 && b.length == 1) return glue;
+ else if (a.length == 1) return concat2_assuming_safe(glue, Text$slice(b, I(2), I(b.length)));
+ else if (b.length == 1) return concat2_assuming_safe(Text$slice(a, I(1), I(a.length - 1)), glue);
else
- return concat2_assuming_safe(
- concat2_assuming_safe(Text$slice(a, I(1), I(a.length-1)), glue),
- Text$slice(b, I(2), I(b.length)));
+ return concat2_assuming_safe(concat2_assuming_safe(Text$slice(a, I(1), I(a.length - 1)), glue),
+ Text$slice(b, I(2), I(b.length)));
}
-public Text_t Text$_concat(int n, Text_t items[n])
-{
+public
+Text_t Text$_concat(int n, Text_t items[n]) {
if (n == 0) return EMPTY_TEXT;
Text_t ret = items[0];
for (int i = 1; i < n; i++) {
- if (items[i].length > 0)
- ret = concat2(ret, items[i]);
+ if (items[i].length > 0) ret = concat2(ret, items[i]);
}
return ret;
}
-public Text_t Text$repeat(Text_t text, Int_t count)
-{
- if (text.length == 0 || Int$is_negative(count))
- return EMPTY_TEXT;
+public
+Text_t Text$repeat(Text_t text, Int_t count) {
+ if (text.length == 0 || Int$is_negative(count)) return EMPTY_TEXT;
Int_t result_len = Int$times(count, I(text.length));
- if (Int$compare_value(result_len, I(1l<<40)) > 0)
- fail("Text repeating would produce too big of an result!");
+ if (Int$compare_value(result_len, I(1l << 40)) > 0) fail("Text repeating would produce too big of an result!");
int64_t count64 = Int64$from_int(count, false);
Text_t ret = text;
@@ -571,19 +557,17 @@ public Text_t Text$repeat(Text_t text, Int_t count)
return ret;
}
-public Int_t Text$width(Text_t text, Text_t language)
-{
- int width = u8_strwidth((const uint8_t*)Text$as_c_string(text), Text$as_c_string(language));
+public
+Int_t Text$width(Text_t text, Text_t language) {
+ int width = u8_strwidth((const uint8_t *)Text$as_c_string(text), Text$as_c_string(language));
return Int$from_int32(width);
}
-static Text_t Text$repeat_to_width(Text_t to_repeat, int64_t target_width, Text_t language)
-{
- if (target_width <= 0)
- return EMPTY_TEXT;
+static Text_t Text$repeat_to_width(Text_t to_repeat, int64_t target_width, Text_t language) {
+ if (target_width <= 0) return EMPTY_TEXT;
const char *lang_str = Text$as_c_string(language);
- int64_t width = (int64_t)u8_strwidth((const uint8_t*)Text$as_c_string(to_repeat), lang_str);
+ int64_t width = (int64_t)u8_strwidth((const uint8_t *)Text$as_c_string(to_repeat), lang_str);
Text_t repeated = EMPTY_TEXT;
int64_t repeated_width = 0;
while (repeated_width + width <= target_width) {
@@ -593,8 +577,8 @@ static Text_t Text$repeat_to_width(Text_t to_repeat, int64_t target_width, Text_
if (repeated_width < target_width) {
for (int64_t i = 0; repeated_width < target_width && i < to_repeat.length; i++) {
- Text_t c = Text$slice(to_repeat, I_small(i+1), I_small(i+1));
- int64_t w = (int64_t)u8_strwidth((const uint8_t*)Text$as_c_string(c), lang_str);
+ Text_t c = Text$slice(to_repeat, I_small(i + 1), I_small(i + 1));
+ int64_t w = (int64_t)u8_strwidth((const uint8_t *)Text$as_c_string(c), lang_str);
if (repeated_width + w > target_width) {
repeated = concat2(repeated, Text$repeat(Text(" "), I(target_width - repeated_width)));
repeated_width = target_width;
@@ -608,35 +592,33 @@ static Text_t Text$repeat_to_width(Text_t to_repeat, int64_t target_width, Text_
return repeated;
}
-public Text_t Text$left_pad(Text_t text, Int_t width, Text_t padding, Text_t language)
-{
- if (padding.length == 0)
- fail("Cannot pad with an empty text!");
+public
+Text_t Text$left_pad(Text_t text, Int_t width, Text_t padding, Text_t language) {
+ if (padding.length == 0) fail("Cannot pad with an empty text!");
int64_t needed = Int64$from_int(width, false) - Int64$from_int(Text$width(text, language), false);
return concat2(Text$repeat_to_width(padding, needed, language), text);
}
-public Text_t Text$right_pad(Text_t text, Int_t width, Text_t padding, Text_t language)
-{
- if (padding.length == 0)
- fail("Cannot pad with an empty text!");
+public
+Text_t Text$right_pad(Text_t text, Int_t width, Text_t padding, Text_t language) {
+ if (padding.length == 0) fail("Cannot pad with an empty text!");
int64_t needed = Int64$from_int(width, false) - Int64$from_int(Text$width(text, language), false);
return concat2(text, Text$repeat_to_width(padding, needed, language));
}
-public Text_t Text$middle_pad(Text_t text, Int_t width, Text_t padding, Text_t language)
-{
- if (padding.length == 0)
- fail("Cannot pad with an empty text!");
+public
+Text_t Text$middle_pad(Text_t text, Int_t width, Text_t padding, Text_t language) {
+ if (padding.length == 0) fail("Cannot pad with an empty text!");
int64_t needed = Int64$from_int(width, false) - Int64$from_int(Text$width(text, language), false);
- return Texts(Text$repeat_to_width(padding, needed/2, language), text, Text$repeat_to_width(padding, (needed+1)/2, language));
+ return Texts(Text$repeat_to_width(padding, needed / 2, language), text,
+ Text$repeat_to_width(padding, (needed + 1) / 2, language));
}
-public Text_t Text$slice(Text_t text, Int_t first_int, Int_t last_int)
-{
+public
+Text_t Text$slice(Text_t text, Int_t first_int, Int_t last_int) {
int64_t first = Int64$from_int(first_int, false);
int64_t last = Int64$from_int(last_int, false);
if (first == 0) fail("Invalid index: 0");
@@ -647,11 +629,9 @@ public Text_t Text$slice(Text_t text, Int_t first_int, Int_t last_int)
if (last > text.length) last = text.length;
- if (first > text.length || last < first)
- return EMPTY_TEXT;
+ if (first > text.length || last < first) return EMPTY_TEXT;
- if (first == 1 && last == text.length)
- return text;
+ if (first == 1 && last == text.length) return text;
while (text.tag == TEXT_CONCAT) {
if (last < text.left->length) {
@@ -662,31 +642,31 @@ public Text_t Text$slice(Text_t text, Int_t first_int, Int_t last_int)
text = *text.right;
} else {
return concat2_assuming_safe(Text$slice(*text.left, I(first), I(text.length)),
- Text$slice(*text.right, I(1), I(last-text.left->length)));
+ Text$slice(*text.right, I(1), I(last - text.left->length)));
}
}
switch (text.tag) {
case TEXT_ASCII: {
return (Text_t){
- .tag=TEXT_ASCII,
- .length=last - first + 1,
- .ascii=text.ascii + (first-1),
+ .tag = TEXT_ASCII,
+ .length = last - first + 1,
+ .ascii = text.ascii + (first - 1),
};
}
case TEXT_GRAPHEMES: {
return (Text_t){
- .tag=TEXT_GRAPHEMES,
- .length=last - first + 1,
- .graphemes=text.graphemes + (first-1),
+ .tag = TEXT_GRAPHEMES,
+ .length = last - first + 1,
+ .graphemes = text.graphemes + (first - 1),
};
}
case TEXT_BLOB: {
Text_t ret = (Text_t){
- .tag=TEXT_BLOB,
- .length=last - first + 1,
- .blob.map=text.blob.map,
- .blob.bytes=text.blob.bytes + (first-1),
+ .tag = TEXT_BLOB,
+ .length = last - first + 1,
+ .blob.map = text.blob.map,
+ .blob.bytes = text.blob.bytes + (first - 1),
};
return ret;
}
@@ -695,48 +675,44 @@ public Text_t Text$slice(Text_t text, Int_t first_int, Int_t last_int)
return EMPTY_TEXT;
}
-public Text_t Text$from(Text_t text, Int_t first)
-{
- return Text$slice(text, first, I_small(-1));
-}
+public
+Text_t Text$from(Text_t text, Int_t first) { return Text$slice(text, first, I_small(-1)); }
-public Text_t Text$to(Text_t text, Int_t last)
-{
- return Text$slice(text, I_small(1), last);
-}
+public
+Text_t Text$to(Text_t text, Int_t last) { return Text$slice(text, I_small(1), last); }
-public Text_t Text$reversed(Text_t text)
-{
+public
+Text_t Text$reversed(Text_t text) {
switch (text.tag) {
case TEXT_ASCII: {
struct Text_s ret = {
- .tag=TEXT_ASCII,
- .length=text.length,
+ .tag = TEXT_ASCII,
+ .length = text.length,
};
ret.ascii = GC_MALLOC_ATOMIC(sizeof(char[ret.length]));
for (int64_t i = 0; i < text.length; i++)
- ((char*)ret.ascii)[text.length-1-i] = text.ascii[i];
+ ((char *)ret.ascii)[text.length - 1 - i] = text.ascii[i];
return ret;
}
case TEXT_GRAPHEMES: {
struct Text_s ret = {
- .tag=TEXT_GRAPHEMES,
- .length=text.length,
+ .tag = TEXT_GRAPHEMES,
+ .length = text.length,
};
ret.graphemes = GC_MALLOC_ATOMIC(sizeof(int32_t[ret.length]));
for (int64_t i = 0; i < text.length; i++)
- ((int32_t*)ret.graphemes)[text.length-1-i] = text.graphemes[i];
+ ((int32_t *)ret.graphemes)[text.length - 1 - i] = text.graphemes[i];
return ret;
}
case TEXT_BLOB: {
struct Text_s ret = {
- .tag=TEXT_BLOB,
- .length=text.length,
- .blob.map=text.blob.map,
+ .tag = TEXT_BLOB,
+ .length = text.length,
+ .blob.map = text.blob.map,
};
ret.blob.bytes = GC_MALLOC_ATOMIC(sizeof(uint8_t[ret.length]));
for (int64_t i = 0; i < text.length; i++)
- ((uint8_t*)ret.blob.bytes)[text.length-1-i] = text.graphemes[i];
+ ((uint8_t *)ret.blob.bytes)[text.length - 1 - i] = text.graphemes[i];
return ret;
}
case TEXT_CONCAT: {
@@ -747,32 +723,30 @@ public Text_t Text$reversed(Text_t text)
return EMPTY_TEXT;
}
-public PUREFUNC Text_t Text$cluster(Text_t text, Int_t index)
-{
- return Text$slice(text, index, index);
-}
+public
+PUREFUNC Text_t Text$cluster(Text_t text, Int_t index) { return Text$slice(text, index, index); }
-static Text_t Text$from_components(List_t graphemes, Table_t unique_clusters)
-{
- size_t blob_size = (
- sizeof(int32_t[unique_clusters.entries.length])
- + sizeof(uint8_t[graphemes.length]));
+static Text_t Text$from_components(List_t graphemes, Table_t unique_clusters) {
+ size_t blob_size = (sizeof(int32_t[unique_clusters.entries.length]) + sizeof(uint8_t[graphemes.length]));
// If blob optimization will save at least 200 bytes:
if (unique_clusters.entries.length <= 256 && blob_size + 200 < sizeof(int32_t[graphemes.length])) {
Text_t ret = {
- .tag=TEXT_BLOB,
- .length=graphemes.length,
- .depth=0,
+ .tag = TEXT_BLOB,
+ .length = graphemes.length,
+ .depth = 0,
};
void *blob = GC_MALLOC_ATOMIC(blob_size);
int32_t *map = blob;
uint8_t *bytes = blob + sizeof(int32_t[unique_clusters.entries.length]);
for (int64_t i = 0; i < unique_clusters.entries.length; i++) {
- struct { int32_t g; uint8_t b; } *entry = unique_clusters.entries.data + i*unique_clusters.entries.stride;
+ struct {
+ int32_t g;
+ uint8_t b;
+ } *entry = unique_clusters.entries.data + i * unique_clusters.entries.stride;
map[entry->b] = entry->g;
}
for (int64_t i = 0; i < graphemes.length; i++) {
- int32_t g = *(int32_t*)(graphemes.data + i*graphemes.stride);
+ int32_t g = *(int32_t *)(graphemes.data + i * graphemes.stride);
uint8_t *byte = Table$get(unique_clusters, &g, Table$info(&Int32$info, &Byte$info));
assert(byte);
bytes[i] = *byte;
@@ -782,15 +756,15 @@ static Text_t Text$from_components(List_t graphemes, Table_t unique_clusters)
return ret;
} else {
return (Text_t){
- .tag=TEXT_GRAPHEMES,
- .length=graphemes.length,
- .graphemes=graphemes.data,
+ .tag = TEXT_GRAPHEMES,
+ .length = graphemes.length,
+ .graphemes = graphemes.data,
};
}
}
-public OptionalText_t Text$from_strn(const char *str, size_t len)
-{
+public
+OptionalText_t Text$from_strn(const char *str, size_t len) {
int64_t ascii_span = 0;
for (size_t i = 0; i < len && isascii(str[i]); i++)
ascii_span++;
@@ -799,52 +773,48 @@ public OptionalText_t Text$from_strn(const char *str, size_t len)
char *copy = GC_MALLOC_ATOMIC(len);
memcpy(copy, str, len);
return (Text_t){
- .tag=TEXT_ASCII,
- .length=ascii_span,
- .ascii=copy,
+ .tag = TEXT_ASCII,
+ .length = ascii_span,
+ .ascii = copy,
};
}
- if (u8_check((uint8_t*)str, len) != NULL)
- return NONE_TEXT;
+ if (u8_check((uint8_t *)str, len) != NULL) return NONE_TEXT;
List_t graphemes = {};
Table_t unique_clusters = {};
- const uint8_t *pos = (const uint8_t*)str;
- const uint8_t *end = (const uint8_t*)&str[len];
+ const uint8_t *pos = (const uint8_t *)str;
+ const uint8_t *end = (const uint8_t *)&str[len];
// Iterate over grapheme clusters
- for (const uint8_t *next; (next=u8_grapheme_next(pos, end)); pos = next) {
+ for (const uint8_t *next; (next = u8_grapheme_next(pos, end)); pos = next) {
uint32_t buf[256];
- size_t u32_len = sizeof(buf)/sizeof(buf[0]);
- uint32_t *u32s = u8_to_u32(pos, (size_t)(next-pos), buf, &u32_len);
+ size_t u32_len = sizeof(buf) / sizeof(buf[0]);
+ uint32_t *u32s = u8_to_u32(pos, (size_t)(next - pos), buf, &u32_len);
uint32_t buf2[256];
- size_t u32_normlen = sizeof(buf2)/sizeof(buf2[0]);
+ size_t u32_normlen = sizeof(buf2) / sizeof(buf2[0]);
uint32_t *u32s_normalized = u32_normalize(UNINORM_NFC, u32s, u32_len, buf2, &u32_normlen);
int32_t g = get_synthetic_grapheme(u32s_normalized, (int64_t)u32_normlen);
List$insert(&graphemes, &g, I(0), sizeof(int32_t));
- Table$get_or_setdefault(&unique_clusters, int32_t, uint8_t, g, (uint8_t)unique_clusters.entries.length, Table$info(&Int32$info, &Byte$info));
+ Table$get_or_setdefault(&unique_clusters, int32_t, uint8_t, g, (uint8_t)unique_clusters.entries.length,
+ Table$info(&Int32$info, &Byte$info));
if (u32s != buf) free(u32s);
if (u32s_normalized != buf2) free(u32s_normalized);
if (unique_clusters.entries.length >= 256) {
- return concat2_assuming_safe(
- Text$from_components(graphemes, unique_clusters),
- Text$from_strn((const char*)next, (size_t)(end-next)));
+ return concat2_assuming_safe(Text$from_components(graphemes, unique_clusters),
+ Text$from_strn((const char *)next, (size_t)(end - next)));
}
}
return Text$from_components(graphemes, unique_clusters);
}
-public OptionalText_t Text$from_str(const char *str)
-{
- return str ? Text$from_strn(str, strlen(str)) : Text("");
-}
+public
+OptionalText_t Text$from_str(const char *str) { return str ? Text$from_strn(str, strlen(str)) : Text(""); }
-static void u8_buf_append(Text_t text, char **buf, int64_t *capacity, int64_t *i)
-{
+static void u8_buf_append(Text_t text, char **buf, int64_t *capacity, int64_t *i) {
switch (text.tag) {
case TEXT_ASCII: {
if (*i + text.length > (int64_t)*capacity) {
@@ -863,7 +833,7 @@ static void u8_buf_append(Text_t text, char **buf, int64_t *capacity, int64_t *i
if (graphemes[g] >= 0) {
uint8_t u8_buf[64];
size_t u8_len = sizeof(u8_buf);
- uint8_t *u8 = u32_to_u8((ucs4_t*)&graphemes[g], 1, u8_buf, &u8_len);
+ uint8_t *u8 = u32_to_u8((ucs4_t *)&graphemes[g], 1, u8_buf, &u8_len);
if (u8 == NULL) fail("Invalid grapheme encountered: ", graphemes[g]);
if (*i + (int64_t)u8_len > (int64_t)*capacity) {
@@ -894,7 +864,7 @@ static void u8_buf_append(Text_t text, char **buf, int64_t *capacity, int64_t *i
if (grapheme >= 0) {
uint8_t u8_buf[64];
size_t u8_len = sizeof(u8_buf);
- uint8_t *u8 = u32_to_u8((ucs4_t*)&grapheme, 1, u8_buf, &u8_len);
+ uint8_t *u8 = u32_to_u8((ucs4_t *)&grapheme, 1, u8_buf, &u8_len);
if (u8 == NULL) fail("Invalid grapheme encountered: ", grapheme);
if (*i + (int64_t)u8_len > (int64_t)*capacity) {
@@ -928,8 +898,8 @@ static void u8_buf_append(Text_t text, char **buf, int64_t *capacity, int64_t *i
}
}
-public char *Text$as_c_string(Text_t text)
-{
+public
+char *Text$as_c_string(Text_t text) {
int64_t capacity = text.length + 1;
char *buf = GC_MALLOC_ATOMIC((size_t)capacity);
int64_t i = 0;
@@ -943,10 +913,9 @@ public char *Text$as_c_string(Text_t text)
return buf;
}
-PUREFUNC public uint64_t Text$hash(const void *obj, const TypeInfo_t *info)
-{
+PUREFUNC public uint64_t Text$hash(const void *obj, const TypeInfo_t *info) {
(void)info;
- Text_t text = *(Text_t*)obj;
+ Text_t text = *(Text_t *)obj;
siphash sh;
siphashinit(&sh, sizeof(int32_t[text.length]));
@@ -959,40 +928,41 @@ PUREFUNC public uint64_t Text$hash(const void *obj, const TypeInfo_t *info)
const char *bytes = text.ascii;
for (int64_t i = 0; i + 1 < text.length; i += 2) {
tmp.chunks[0] = (int32_t)bytes[i];
- tmp.chunks[1] = (int32_t)bytes[i+1];
+ tmp.chunks[1] = (int32_t)bytes[i + 1];
siphashadd64bits(&sh, tmp.whole);
}
- int32_t last = text.length & 0x1 ? (int32_t)bytes[text.length-1] : 0; // Odd number of graphemes
+ int32_t last = text.length & 0x1 ? (int32_t)bytes[text.length - 1] : 0; // Odd number of graphemes
return siphashfinish_last_part(&sh, (uint64_t)last);
}
case TEXT_GRAPHEMES: {
const int32_t *graphemes = text.graphemes;
for (int64_t i = 0; i + 1 < text.length; i += 2) {
tmp.chunks[0] = graphemes[i];
- tmp.chunks[1] = graphemes[i+1];
+ tmp.chunks[1] = graphemes[i + 1];
siphashadd64bits(&sh, tmp.whole);
}
- int32_t last = text.length & 0x1 ? graphemes[text.length-1] : 0; // Odd number of graphemes
+ int32_t last = text.length & 0x1 ? graphemes[text.length - 1] : 0; // Odd number of graphemes
return siphashfinish_last_part(&sh, (uint64_t)last);
}
case TEXT_BLOB: {
for (int64_t i = 0; i + 1 < text.length; i += 2) {
tmp.chunks[0] = text.blob.map[text.blob.bytes[i]];
- tmp.chunks[1] = text.blob.map[text.blob.bytes[i+1]];
+ tmp.chunks[1] = text.blob.map[text.blob.bytes[i + 1]];
siphashadd64bits(&sh, tmp.whole);
}
- int32_t last = text.length & 0x1 ? text.blob.map[text.blob.bytes[text.length-1]] : 0; // Odd number of graphemes
+ int32_t last =
+ text.length & 0x1 ? text.blob.map[text.blob.bytes[text.length - 1]] : 0; // Odd number of graphemes
return siphashfinish_last_part(&sh, (uint64_t)last);
}
case TEXT_CONCAT: {
TextIter_t state = NEW_TEXT_ITER_STATE(text);
for (int64_t i = 0; i + 1 < text.length; i += 2) {
tmp.chunks[0] = Text$get_grapheme_fast(&state, i);
- tmp.chunks[1] = Text$get_grapheme_fast(&state, i+1);
+ tmp.chunks[1] = Text$get_grapheme_fast(&state, i + 1);
siphashadd64bits(&sh, tmp.whole);
}
- int32_t last = (text.length & 0x1) ? Text$get_grapheme_fast(&state, text.length-1) : 0;
+ int32_t last = (text.length & 0x1) ? Text$get_grapheme_fast(&state, text.length - 1) : 0;
return siphashfinish_last_part(&sh, (uint64_t)last);
}
default: errx(1, "Invalid text");
@@ -1000,8 +970,8 @@ PUREFUNC public uint64_t Text$hash(const void *obj, const TypeInfo_t *info)
return 0;
}
-public int32_t Text$get_grapheme_fast(TextIter_t *state, int64_t index)
-{
+public
+int32_t Text$get_grapheme_fast(TextIter_t *state, int64_t index) {
if (index < 0) return 0;
if (index >= state->stack[0].text.length) return 0;
@@ -1051,18 +1021,17 @@ public int32_t Text$get_grapheme_fast(TextIter_t *state, int64_t index)
return 0;
}
-public uint32_t Text$get_main_grapheme_fast(TextIter_t *state, int64_t index)
-{
+public
+uint32_t Text$get_main_grapheme_fast(TextIter_t *state, int64_t index) {
int32_t g = Text$get_grapheme_fast(state, index);
return (g) >= 0 ? (ucs4_t)(g) : synthetic_graphemes[-(g)-1].main_codepoint;
}
-PUREFUNC public int32_t Text$compare(const void *va, const void *vb, const TypeInfo_t *info)
-{
+PUREFUNC public int32_t Text$compare(const void *va, const void *vb, const TypeInfo_t *info) {
(void)info;
if (va == vb) return 0;
- const Text_t a = *(const Text_t*)va;
- const Text_t b = *(const Text_t*)vb;
+ const Text_t a = *(const Text_t *)va;
+ const Text_t b = *(const Text_t *)vb;
// TODO: make this smarter and more efficient
int64_t len = MAX(a.length, b.length);
@@ -1073,31 +1042,21 @@ PUREFUNC public int32_t Text$compare(const void *va, const void *vb, const TypeI
if (ai == bi) continue;
int32_t cmp;
if (ai > 0 && bi > 0) {
- cmp = u32_cmp((ucs4_t*)&ai, (ucs4_t*)&bi, 1);
+ cmp = u32_cmp((ucs4_t *)&ai, (ucs4_t *)&bi, 1);
} else if (ai > 0) {
- cmp = u32_cmp2(
- (ucs4_t*)&ai, 1,
- GRAPHEME_CODEPOINTS(bi),
- NUM_GRAPHEME_CODEPOINTS(bi));
+ cmp = u32_cmp2((ucs4_t *)&ai, 1, GRAPHEME_CODEPOINTS(bi), NUM_GRAPHEME_CODEPOINTS(bi));
} else if (bi > 0) {
- cmp = u32_cmp2(
- GRAPHEME_CODEPOINTS(ai),
- NUM_GRAPHEME_CODEPOINTS(ai),
- (ucs4_t*)&bi, 1);
+ cmp = u32_cmp2(GRAPHEME_CODEPOINTS(ai), NUM_GRAPHEME_CODEPOINTS(ai), (ucs4_t *)&bi, 1);
} else {
- cmp = u32_cmp2(
- GRAPHEME_CODEPOINTS(ai),
- NUM_GRAPHEME_CODEPOINTS(ai),
- GRAPHEME_CODEPOINTS(bi),
- NUM_GRAPHEME_CODEPOINTS(bi));
+ cmp = u32_cmp2(GRAPHEME_CODEPOINTS(ai), NUM_GRAPHEME_CODEPOINTS(ai), GRAPHEME_CODEPOINTS(bi),
+ NUM_GRAPHEME_CODEPOINTS(bi));
}
if (cmp != 0) return cmp;
}
return 0;
}
-bool _matches(TextIter_t *text_state, TextIter_t *target_state, int64_t pos)
-{
+bool _matches(TextIter_t *text_state, TextIter_t *target_state, int64_t pos) {
for (int64_t i = 0; i < target_state->stack[0].text.length; i++) {
int32_t text_i = Text$get_grapheme_fast(text_state, pos + i);
int32_t prefix_i = Text$get_grapheme_fast(target_state, i);
@@ -1106,10 +1065,8 @@ bool _matches(TextIter_t *text_state, TextIter_t *target_state, int64_t pos)
return true;
}
-PUREFUNC public bool Text$starts_with(Text_t text, Text_t prefix, Text_t *remainder)
-{
- if (text.length < prefix.length)
- return false;
+PUREFUNC public bool Text$starts_with(Text_t text, Text_t prefix, Text_t *remainder) {
+ if (text.length < prefix.length) return false;
TextIter_t text_state = NEW_TEXT_ITER_STATE(text), prefix_state = NEW_TEXT_ITER_STATE(prefix);
if (_matches(&text_state, &prefix_state, 0)) {
if (remainder) *remainder = Text$from(text, Int$from_int64(prefix.length + 1));
@@ -1120,10 +1077,8 @@ PUREFUNC public bool Text$starts_with(Text_t text, Text_t prefix, Text_t *remain
}
}
-PUREFUNC public bool Text$ends_with(Text_t text, Text_t suffix, Text_t *remainder)
-{
- if (text.length < suffix.length)
- return false;
+PUREFUNC public bool Text$ends_with(Text_t text, Text_t suffix, Text_t *remainder) {
+ if (text.length < suffix.length) return false;
TextIter_t text_state = NEW_TEXT_ITER_STATE(text), suffix_state = NEW_TEXT_ITER_STATE(suffix);
if (_matches(&text_state, &suffix_state, text.length - suffix.length)) {
if (remainder) *remainder = Text$to(text, Int$from_int64(text.length - suffix.length));
@@ -1134,18 +1089,17 @@ PUREFUNC public bool Text$ends_with(Text_t text, Text_t suffix, Text_t *remainde
}
}
-public Text_t Text$without_prefix(Text_t text, Text_t prefix)
-{
+public
+Text_t Text$without_prefix(Text_t text, Text_t prefix) {
return Text$starts_with(text, prefix, NULL) ? Text$slice(text, I(prefix.length + 1), I(text.length)) : text;
}
-public Text_t Text$without_suffix(Text_t text, Text_t suffix)
-{
+public
+Text_t Text$without_suffix(Text_t text, Text_t suffix) {
return Text$ends_with(text, suffix, NULL) ? Text$slice(text, I(1), I(text.length - suffix.length)) : text;
}
-static bool _has_grapheme(TextIter_t *text, int32_t g)
-{
+static bool _has_grapheme(TextIter_t *text, int32_t g) {
for (int64_t t = 0; t < text->stack[0].text.length; t++) {
if (g == Text$get_grapheme_fast(text, t)) {
return true;
@@ -1154,8 +1108,8 @@ static bool _has_grapheme(TextIter_t *text, int32_t g)
return false;
}
-public Text_t Text$trim(Text_t text, Text_t to_trim, bool left, bool right)
-{
+public
+Text_t Text$trim(Text_t text, Text_t to_trim, bool left, bool right) {
int64_t first = 0;
TextIter_t text_state = NEW_TEXT_ITER_STATE(text), trim_state = NEW_TEXT_ITER_STATE(to_trim);
if (left) {
@@ -1163,28 +1117,29 @@ public Text_t Text$trim(Text_t text, Text_t to_trim, bool left, bool right)
first += 1;
}
}
- int64_t last = text.length-1;
+ int64_t last = text.length - 1;
if (right) {
while (last >= first && _has_grapheme(&trim_state, Text$get_grapheme_fast(&text_state, last))) {
last -= 1;
}
}
- return (first != 0 || last != text.length-1) ? Text$slice(text, I(first+1), I(last+1)) : text;
+ return (first != 0 || last != text.length - 1) ? Text$slice(text, I(first + 1), I(last + 1)) : text;
}
-public Text_t Text$translate(Text_t text, Table_t translations)
-{
+public
+Text_t Text$translate(Text_t text, Table_t translations) {
TextIter_t text_state = NEW_TEXT_ITER_STATE(text);
Text_t result = EMPTY_TEXT;
int64_t span_start = 0;
List_t replacement_list = translations.entries;
- for (int64_t i = 0; i < text.length; ) {
+ for (int64_t i = 0; i < text.length;) {
for (int64_t r = 0; r < replacement_list.length; r++) {
- struct { Text_t target, replacement; } *entry = replacement_list.data + r*replacement_list.stride;
+ struct {
+ Text_t target, replacement;
+ } *entry = replacement_list.data + r * replacement_list.stride;
TextIter_t target_state = NEW_TEXT_ITER_STATE(entry->target);
if (_matches(&text_state, &target_state, i)) {
- if (i > span_start)
- result = concat2(result, Text$slice(text, I(span_start+1), I(i)));
+ if (i > span_start) result = concat2(result, Text$slice(text, I(span_start + 1), I(i)));
result = concat2(result, entry->replacement);
i += entry->target.length;
@@ -1193,22 +1148,21 @@ public Text_t Text$translate(Text_t text, Table_t translations)
}
}
i += 1;
- found_match: continue;
+ found_match:
+ continue;
}
- if (span_start < text.length)
- result = concat2(result, Text$slice(text, I(span_start+1), I(text.length)));
+ if (span_start < text.length) result = concat2(result, Text$slice(text, I(span_start + 1), I(text.length)));
return result;
}
-public Text_t Text$replace(Text_t text, Text_t target, Text_t replacement)
-{
+public
+Text_t Text$replace(Text_t text, Text_t target, Text_t replacement) {
TextIter_t text_state = NEW_TEXT_ITER_STATE(text), target_state = NEW_TEXT_ITER_STATE(target);
Text_t result = EMPTY_TEXT;
int64_t span_start = 0;
- for (int64_t i = 0; i < text.length; ) {
+ for (int64_t i = 0; i < text.length;) {
if (_matches(&text_state, &target_state, i)) {
- if (i > span_start)
- result = concat2(result, Text$slice(text, I(span_start+1), I(i)));
+ if (i > span_start) result = concat2(result, Text$slice(text, I(span_start + 1), I(i)));
result = concat2(result, replacement);
i += target.length;
@@ -1217,34 +1171,31 @@ public Text_t Text$replace(Text_t text, Text_t target, Text_t replacement)
i += 1;
}
}
- if (span_start < text.length)
- result = concat2(result, Text$slice(text, I(span_start+1), I(text.length)));
+ if (span_start < text.length) result = concat2(result, Text$slice(text, I(span_start + 1), I(text.length)));
return result;
}
-public PUREFUNC bool Text$has(Text_t text, Text_t target)
-{
+public
+PUREFUNC bool Text$has(Text_t text, Text_t target) {
TextIter_t text_state = NEW_TEXT_ITER_STATE(text), target_state = NEW_TEXT_ITER_STATE(target);
for (int64_t i = 0; i < text.length; i++) {
- if (_matches(&text_state, &target_state, i))
- return true;
+ if (_matches(&text_state, &target_state, i)) return true;
}
return false;
}
-public List_t Text$split(Text_t text, Text_t delimiters)
-{
- if (delimiters.length == 0)
- return Text$clusters(text);
+public
+List_t Text$split(Text_t text, Text_t delimiters) {
+ if (delimiters.length == 0) return Text$clusters(text);
TextIter_t text_state = NEW_TEXT_ITER_STATE(text), delim_state = NEW_TEXT_ITER_STATE(delimiters);
List_t splits = {};
- for (int64_t i = 0; i < text.length; ) {
+ for (int64_t i = 0; i < text.length;) {
int64_t span_len = 0;
while (i + span_len < text.length && !_matches(&text_state, &delim_state, i + span_len)) {
span_len += 1;
}
- Text_t slice = Text$slice(text, I(i+1), I(i+span_len));
+ Text_t slice = Text$slice(text, I(i + 1), I(i + span_len));
List$insert(&splits, &slice, I(0), sizeof(slice));
i += span_len + delimiters.length;
if (i == text.length) {
@@ -1255,20 +1206,20 @@ public List_t Text$split(Text_t text, Text_t delimiters)
return splits;
}
-public List_t Text$split_any(Text_t text, Text_t delimiters)
-{
- if (delimiters.length == 0)
- return List(text);
+public
+List_t Text$split_any(Text_t text, Text_t delimiters) {
+ if (delimiters.length == 0) return List(text);
TextIter_t text_state = NEW_TEXT_ITER_STATE(text), delim_state = NEW_TEXT_ITER_STATE(delimiters);
List_t splits = {};
- for (int64_t i = 0; i < text.length; ) {
+ for (int64_t i = 0; i < text.length;) {
int64_t span_len = 0;
- while (i + span_len < text.length && !_has_grapheme(&delim_state, Text$get_grapheme_fast(&text_state, i + span_len))) {
+ while (i + span_len < text.length
+ && !_has_grapheme(&delim_state, Text$get_grapheme_fast(&text_state, i + span_len))) {
span_len += 1;
}
bool trailing_delim = i + span_len < text.length;
- Text_t slice = Text$slice(text, I(i+1), I(i+span_len));
+ Text_t slice = Text$slice(text, I(i + 1), I(i + span_len));
List$insert(&splits, &slice, I(0), sizeof(slice));
i += span_len + 1;
while (i < text.length && _has_grapheme(&delim_state, Text$get_grapheme_fast(&text_state, i))) {
@@ -1288,8 +1239,7 @@ typedef struct {
Text_t delimiter;
} split_iter_state_t;
-static OptionalText_t next_split(split_iter_state_t *state)
-{
+static OptionalText_t next_split(split_iter_state_t *state) {
Text_t text = state->state.stack[0].text;
if (state->i >= text.length) {
if (state->delimiter.length > 0 && state->i == text.length) { // special case
@@ -1310,21 +1260,20 @@ static OptionalText_t next_split(split_iter_state_t *state)
while (i + span_len < text.length && !_matches(&state->state, &delim_state, i + span_len)) {
span_len += 1;
}
- Text_t slice = Text$slice(text, I(i+1), I(i+span_len));
+ Text_t slice = Text$slice(text, I(i + 1), I(i + span_len));
state->i = i + span_len + state->delimiter.length;
return slice;
}
-public Closure_t Text$by_split(Text_t text, Text_t delimiter)
-{
+public
+Closure_t Text$by_split(Text_t text, Text_t delimiter) {
return (Closure_t){
- .fn=(void*)next_split,
- .userdata=new(split_iter_state_t, .state=NEW_TEXT_ITER_STATE(text), .i=0, .delimiter=delimiter),
+ .fn = (void *)next_split,
+ .userdata = new (split_iter_state_t, .state = NEW_TEXT_ITER_STATE(text), .i = 0, .delimiter = delimiter),
};
}
-static OptionalText_t next_split_any(split_iter_state_t *state)
-{
+static OptionalText_t next_split_any(split_iter_state_t *state) {
Text_t text = state->state.stack[0].text;
if (state->i >= text.length) {
if (state->delimiter.length > 0 && state->i == text.length) { // special case
@@ -1335,7 +1284,7 @@ static OptionalText_t next_split_any(split_iter_state_t *state)
}
if (state->delimiter.length == 0) { // special case
- Text_t ret = Text$cluster(text, I(state->i+1));
+ Text_t ret = Text$cluster(text, I(state->i + 1));
state->i += 1;
return ret;
}
@@ -1343,10 +1292,11 @@ static OptionalText_t next_split_any(split_iter_state_t *state)
TextIter_t delim_state = NEW_TEXT_ITER_STATE(state->delimiter);
int64_t i = state->i;
int64_t span_len = 0;
- while (i + span_len < text.length && !_has_grapheme(&delim_state, Text$get_grapheme_fast(&state->state, i + span_len))) {
+ while (i + span_len < text.length
+ && !_has_grapheme(&delim_state, Text$get_grapheme_fast(&state->state, i + span_len))) {
span_len += 1;
}
- Text_t slice = Text$slice(text, I(i+1), I(i+span_len));
+ Text_t slice = Text$slice(text, I(i + 1), I(i + span_len));
i += span_len + 1;
while (i < text.length && _has_grapheme(&delim_state, Text$get_grapheme_fast(&state->state, i))) {
i += 1;
@@ -1355,18 +1305,16 @@ static OptionalText_t next_split_any(split_iter_state_t *state)
return slice;
}
-public Closure_t Text$by_split_any(Text_t text, Text_t delimiters)
-{
+public
+Closure_t Text$by_split_any(Text_t text, Text_t delimiters) {
return (Closure_t){
- .fn=(void*)next_split_any,
- .userdata=new(split_iter_state_t, .state=NEW_TEXT_ITER_STATE(text), .i=0, .delimiter=delimiters),
+ .fn = (void *)next_split_any,
+ .userdata = new (split_iter_state_t, .state = NEW_TEXT_ITER_STATE(text), .i = 0, .delimiter = delimiters),
};
}
-PUREFUNC public bool Text$equal_values(Text_t a, Text_t b)
-{
- if (a.length != b.length)
- return false;
+PUREFUNC public bool Text$equal_values(Text_t a, Text_t b) {
+ if (a.length != b.length) return false;
int64_t len = a.length;
TextIter_t a_state = NEW_TEXT_ITER_STATE(a), b_state = NEW_TEXT_ITER_STATE(b);
// TODO: make this smarter and more efficient
@@ -1378,17 +1326,14 @@ PUREFUNC public bool Text$equal_values(Text_t a, Text_t b)
return true;
}
-PUREFUNC public bool Text$equal(const void *a, const void *b, const TypeInfo_t *info)
-{
+PUREFUNC public bool Text$equal(const void *a, const void *b, const TypeInfo_t *info) {
(void)info;
if (a == b) return true;
- return Text$equal_values(*(Text_t*)a, *(Text_t*)b);
+ return Text$equal_values(*(Text_t *)a, *(Text_t *)b);
}
-PUREFUNC public bool Text$equal_ignoring_case(Text_t a, Text_t b, Text_t language)
-{
- if (a.length != b.length)
- return false;
+PUREFUNC public bool Text$equal_ignoring_case(Text_t a, Text_t b, Text_t language) {
+ if (a.length != b.length) return false;
int64_t len = a.length;
TextIter_t a_state = NEW_TEXT_ITER_STATE(a), b_state = NEW_TEXT_ITER_STATE(b);
const char *uc_language = Text$as_c_string(language);
@@ -1396,76 +1341,79 @@ PUREFUNC public bool Text$equal_ignoring_case(Text_t a, Text_t b, Text_t languag
int32_t ai = Text$get_grapheme_fast(&a_state, i);
int32_t bi = Text$get_grapheme_fast(&b_state, i);
if (ai != bi) {
- const ucs4_t *a_codepoints = ai >= 0 ? (ucs4_t*)&ai : GRAPHEME_CODEPOINTS(ai);
+ const ucs4_t *a_codepoints = ai >= 0 ? (ucs4_t *)&ai : GRAPHEME_CODEPOINTS(ai);
int64_t a_len = ai >= 0 ? 1 : NUM_GRAPHEME_CODEPOINTS(ai);
- const ucs4_t *b_codepoints = bi >= 0 ? (ucs4_t*)&bi : GRAPHEME_CODEPOINTS(bi);
+ const ucs4_t *b_codepoints = bi >= 0 ? (ucs4_t *)&bi : GRAPHEME_CODEPOINTS(bi);
int64_t b_len = bi >= 0 ? 1 : NUM_GRAPHEME_CODEPOINTS(bi);
int cmp = 0;
(void)u32_casecmp(a_codepoints, (size_t)a_len, b_codepoints, (size_t)b_len, uc_language, UNINORM_NFC, &cmp);
- if (cmp != 0)
- return false;
+ if (cmp != 0) return false;
}
}
return true;
}
-public Text_t Text$upper(Text_t text, Text_t language)
-{
+public
+Text_t Text$upper(Text_t text, Text_t language) {
if (text.length == 0) return text;
List_t codepoints = Text$utf32_codepoints(text);
const char *uc_language = Text$as_c_string(language);
size_t out_len = 0;
ucs4_t *upper = u32_toupper(codepoints.data, (size_t)codepoints.length, uc_language, UNINORM_NFC, NULL, &out_len);
- Text_t ret = Text$from_codepoints((List_t){.data=upper, .length=(int64_t)out_len, .stride=sizeof(int32_t)});
+ Text_t ret = Text$from_codepoints((List_t){.data = upper, .length = (int64_t)out_len, .stride = sizeof(int32_t)});
return ret;
}
-public Text_t Text$lower(Text_t text, Text_t language)
-{
+public
+Text_t Text$lower(Text_t text, Text_t language) {
if (text.length == 0) return text;
List_t codepoints = Text$utf32_codepoints(text);
const char *uc_language = Text$as_c_string(language);
size_t out_len = 0;
ucs4_t *lower = u32_tolower(codepoints.data, (size_t)codepoints.length, uc_language, UNINORM_NFC, NULL, &out_len);
- Text_t ret = Text$from_codepoints((List_t){.data=lower, .length=(int64_t)out_len, .stride=sizeof(int32_t)});
+ Text_t ret = Text$from_codepoints((List_t){.data = lower, .length = (int64_t)out_len, .stride = sizeof(int32_t)});
return ret;
}
-public Text_t Text$title(Text_t text, Text_t language)
-{
+public
+Text_t Text$title(Text_t text, Text_t language) {
if (text.length == 0) return text;
List_t codepoints = Text$utf32_codepoints(text);
const char *uc_language = Text$as_c_string(language);
size_t out_len = 0;
ucs4_t *title = u32_totitle(codepoints.data, (size_t)codepoints.length, uc_language, UNINORM_NFC, NULL, &out_len);
- Text_t ret = Text$from_codepoints((List_t){.data=title, .length=(int64_t)out_len, .stride=sizeof(int32_t)});
+ Text_t ret = Text$from_codepoints((List_t){.data = title, .length = (int64_t)out_len, .stride = sizeof(int32_t)});
return ret;
}
-public Text_t Text$quoted(Text_t text, bool colorize, Text_t quotation_mark)
-{
- if (quotation_mark.length != 1)
- fail("Invalid quote text: ", quotation_mark, " (must have length == 1)");
+public
+Text_t Text$quoted(Text_t text, bool colorize, Text_t quotation_mark) {
+ if (quotation_mark.length != 1) fail("Invalid quote text: ", quotation_mark, " (must have length == 1)");
Text_t ret = colorize ? Text("\x1b[35m") : EMPTY_TEXT;
- if (!Text$equal_values(quotation_mark, Text("\"")) && !Text$equal_values(quotation_mark, Text("'")) && !Text$equal_values(quotation_mark, Text("`")))
+ if (!Text$equal_values(quotation_mark, Text("\"")) && !Text$equal_values(quotation_mark, Text("'"))
+ && !Text$equal_values(quotation_mark, Text("`")))
ret = concat2_assuming_safe(ret, Text("$"));
ret = concat2_assuming_safe(ret, quotation_mark);
int32_t quote_char = Text$get_grapheme(quotation_mark, 0);
-#define flush_unquoted() ({ \
- if (unquoted_span > 0) { \
- ret = concat2_assuming_safe(ret, Text$slice(text, I(i-unquoted_span+1), I(i))); \
- unquoted_span = 0; \
- } })
-#define add_escaped(str) ({ \
- flush_unquoted(); \
- if (colorize) ret = concat2_assuming_safe(ret, Text("\x1b[34;1m")); \
- ret = concat2_assuming_safe(ret, Text("\\" str)); \
- if (colorize) ret = concat2_assuming_safe(ret, Text("\x1b[0;35m")); })
+#define flush_unquoted() \
+ ({ \
+ if (unquoted_span > 0) { \
+ ret = concat2_assuming_safe(ret, Text$slice(text, I(i - unquoted_span + 1), I(i))); \
+ unquoted_span = 0; \
+ } \
+ })
+#define add_escaped(str) \
+ ({ \
+ flush_unquoted(); \
+ if (colorize) ret = concat2_assuming_safe(ret, Text("\x1b[34;1m")); \
+ ret = concat2_assuming_safe(ret, Text("\\" str)); \
+ if (colorize) ret = concat2_assuming_safe(ret, Text("\x1b[0;35m")); \
+ })
TextIter_t state = NEW_TEXT_ITER_STATE(text);
int64_t unquoted_span = 0;
int64_t i = 0;
@@ -1488,8 +1436,10 @@ public Text_t Text$quoted(Text_t text, bool colorize, Text_t quotation_mark)
add_escaped("$");
break;
}
- case '\x00' ... '\x06': case '\x0E' ... '\x1A':
- case '\x1C' ... '\x1F': case '\x7F' ... '\x7F': {
+ case '\x00' ... '\x06':
+ case '\x0E' ... '\x1A':
+ case '\x1C' ... '\x1F':
+ case '\x7F' ... '\x7F': {
flush_unquoted();
if (colorize) ret = concat2_assuming_safe(ret, Text("\x1b[34;1m"));
ret = concat2_assuming_safe(ret, Text("\\x"));
@@ -1499,8 +1449,7 @@ public Text_t Text$quoted(Text_t text, bool colorize, Text_t quotation_mark)
'\0',
};
ret = concat2_assuming_safe(ret, Text$from_strn(tmp, 2));
- if (colorize)
- ret = concat2_assuming_safe(ret, Text("\x1b[0;35m"));
+ if (colorize) ret = concat2_assuming_safe(ret, Text("\x1b[0;35m"));
break;
}
default: {
@@ -1522,21 +1471,19 @@ public Text_t Text$quoted(Text_t text, bool colorize, Text_t quotation_mark)
#undef flush_unquoted
ret = concat2_assuming_safe(ret, quotation_mark);
- if (colorize)
- ret = concat2_assuming_safe(ret, Text("\x1b[m"));
+ if (colorize) ret = concat2_assuming_safe(ret, Text("\x1b[m"));
return ret;
}
-public Text_t Text$as_text(const void *vtext, bool colorize, const TypeInfo_t *info)
-{
+public
+Text_t Text$as_text(const void *vtext, bool colorize, const TypeInfo_t *info) {
(void)info;
if (!vtext) return info && info->TextInfo.lang ? Text$from_str(info->TextInfo.lang) : Text("Text");
- Text_t text = *(Text_t*)vtext;
+ Text_t text = *(Text_t *)vtext;
// Figure out the best quotation mark to use:
- bool has_double_quote = false, has_backtick = false,
- has_single_quote = false, needs_escapes = false;
+ bool has_double_quote = false, has_backtick = false, has_single_quote = false, needs_escapes = false;
TextIter_t state = NEW_TEXT_ITER_STATE(text);
for (int64_t i = 0; i < text.length; i++) {
int32_t g = Text$get_grapheme_fast(&state, i);
@@ -1554,39 +1501,33 @@ public Text_t Text$as_text(const void *vtext, bool colorize, const TypeInfo_t *i
// needing to escape them by using single quotes, but only if we don't have
// single quotes or need to escape anything else (because single quotes
// don't have interpolation):
- if (has_double_quote && !has_single_quote)
- quote = Text("'");
+ if (has_double_quote && !has_single_quote) quote = Text("'");
// If there is a double quote, but no backtick, we can save a bit of
// escaping by using backtick instead of double quote:
- else if (has_double_quote && has_single_quote && !has_backtick && !needs_escapes)
- quote = Text("`");
+ else if (has_double_quote && has_single_quote && !has_backtick && !needs_escapes) quote = Text("`");
// Otherwise fall back to double quotes as the default quoting style:
- else
- quote = Text("\"");
+ else quote = Text("\"");
Text_t as_text = Text$quoted(text, colorize, quote);
if (info && info->TextInfo.lang && info != &Text$info)
- as_text = Text$concat(
- colorize ? Text("\x1b[1m$") : Text("$"),
- Text$from_str(info->TextInfo.lang),
- colorize ? Text("\x1b[0m") : Text(""),
- as_text);
+ as_text = Text$concat(colorize ? Text("\x1b[1m$") : Text("$"), Text$from_str(info->TextInfo.lang),
+ colorize ? Text("\x1b[0m") : Text(""), as_text);
return as_text;
}
-public Text_t Text$join(Text_t glue, List_t pieces)
-{
+public
+Text_t Text$join(Text_t glue, List_t pieces) {
if (pieces.length == 0) return EMPTY_TEXT;
- Text_t result = *(Text_t*)pieces.data;
+ Text_t result = *(Text_t *)pieces.data;
for (int64_t i = 1; i < pieces.length; i++) {
- result = Text$concat(result, glue, *(Text_t*)(pieces.data + i*pieces.stride));
+ result = Text$concat(result, glue, *(Text_t *)(pieces.data + i * pieces.stride));
}
return result;
}
-public List_t Text$clusters(Text_t text)
-{
+public
+List_t Text$clusters(Text_t text) {
List_t clusters = {};
for (int64_t i = 1; i <= text.length; i++) {
Text_t cluster = Text$slice(text, I(i), I(i));
@@ -1595,9 +1536,9 @@ public List_t Text$clusters(Text_t text)
return clusters;
}
-public List_t Text$utf32_codepoints(Text_t text)
-{
- List_t codepoints = {.atomic=1};
+public
+List_t Text$utf32_codepoints(Text_t text) {
+ List_t codepoints = {.atomic = 1};
TextIter_t state = NEW_TEXT_ITER_STATE(text);
for (int64_t i = 0; i < text.length; i++) {
int32_t grapheme = Text$get_grapheme_fast(&state, i);
@@ -1613,24 +1554,23 @@ public List_t Text$utf32_codepoints(Text_t text)
return codepoints;
}
-public List_t Text$utf8_bytes(Text_t text)
-{
+public
+List_t Text$utf8_bytes(Text_t text) {
const char *str = Text$as_c_string(text);
- return (List_t){.length=(int64_t)strlen(str), .stride=1, .atomic=1, .data=(void*)str};
+ return (List_t){.length = (int64_t)strlen(str), .stride = 1, .atomic = 1, .data = (void *)str};
}
-static INLINE const char *codepoint_name(ucs4_t c)
-{
+static INLINE const char *codepoint_name(ucs4_t c) {
char *name = GC_MALLOC_ATOMIC(UNINAME_MAX);
char *found_name = unicode_character_name(c, name);
if (found_name) return found_name;
const uc_block_t *block = uc_block(c);
assert(block);
- return String(block->name, "-", hex(c, .no_prefix=true, .uppercase=true));
+ return String(block->name, "-", hex(c, .no_prefix = true, .uppercase = true));
}
-public List_t Text$codepoint_names(Text_t text)
-{
+public
+List_t Text$codepoint_names(Text_t text) {
List_t names = {};
TextIter_t state = NEW_TEXT_ITER_STATE(text);
for (int64_t i = 0; i < text.length; i++) {
@@ -1650,81 +1590,78 @@ public List_t Text$codepoint_names(Text_t text)
return names;
}
-public Text_t Text$from_codepoints(List_t codepoints)
-{
- if (codepoints.stride != sizeof(uint32_t))
- List$compact(&codepoints, sizeof(uint32_t));
+public
+Text_t Text$from_codepoints(List_t codepoints) {
+ if (codepoints.stride != sizeof(uint32_t)) List$compact(&codepoints, sizeof(uint32_t));
List_t graphemes = {};
Table_t unique_clusters = {};
- const uint32_t *pos = (const uint32_t*)codepoints.data;
- const uint32_t *end = (const uint32_t*)&pos[codepoints.length];
+ const uint32_t *pos = (const uint32_t *)codepoints.data;
+ const uint32_t *end = (const uint32_t *)&pos[codepoints.length];
// Iterate over grapheme clusters
- for (const uint32_t *next; (next=u32_grapheme_next(pos, end)); pos = next) {
+ for (const uint32_t *next; (next = u32_grapheme_next(pos, end)); pos = next) {
// Buffer for normalized cluster:
uint32_t buf[256];
- size_t u32_normlen = sizeof(buf)/sizeof(buf[0]);
- uint32_t *u32s_normalized = u32_normalize(UNINORM_NFC, pos, (size_t)(next-pos), buf, &u32_normlen);
+ size_t u32_normlen = sizeof(buf) / sizeof(buf[0]);
+ uint32_t *u32s_normalized = u32_normalize(UNINORM_NFC, pos, (size_t)(next - pos), buf, &u32_normlen);
int32_t g = get_synthetic_grapheme(u32s_normalized, (int64_t)u32_normlen);
List$insert(&graphemes, &g, I(0), sizeof(int32_t));
- Table$get_or_setdefault(
- &unique_clusters, int32_t, uint8_t, g, (uint8_t)unique_clusters.entries.length,
- Table$info(&Int32$info, &Byte$info));
+ Table$get_or_setdefault(&unique_clusters, int32_t, uint8_t, g, (uint8_t)unique_clusters.entries.length,
+ Table$info(&Int32$info, &Byte$info));
if (u32s_normalized != buf) free(u32s_normalized);
if (unique_clusters.entries.length == 256) {
List_t remaining_codepoints = {
- .length=(int64_t)(end-next),
- .data=(void*)next,
- .stride=sizeof(int32_t),
+ .length = (int64_t)(end - next),
+ .data = (void *)next,
+ .stride = sizeof(int32_t),
};
- return concat2_assuming_safe(Text$from_components(graphemes, unique_clusters), Text$from_codepoints(remaining_codepoints));
+ return concat2_assuming_safe(Text$from_components(graphemes, unique_clusters),
+ Text$from_codepoints(remaining_codepoints));
}
}
return Text$from_components(graphemes, unique_clusters);
}
-public OptionalText_t Text$from_codepoint_names(List_t codepoint_names)
-{
+public
+OptionalText_t Text$from_codepoint_names(List_t codepoint_names) {
List_t codepoints = {};
for (int64_t i = 0; i < codepoint_names.length; i++) {
- Text_t *name = ((Text_t*)(codepoint_names.data + i*codepoint_names.stride));
+ Text_t *name = ((Text_t *)(codepoint_names.data + i * codepoint_names.stride));
const char *name_str = Text$as_c_string(*name);
ucs4_t codepoint = unicode_name_character(name_str);
- if (codepoint == UNINAME_INVALID)
- return NONE_TEXT;
+ if (codepoint == UNINAME_INVALID) return NONE_TEXT;
List$insert(&codepoints, &codepoint, I_small(0), sizeof(ucs4_t));
}
return Text$from_codepoints(codepoints);
}
-public OptionalText_t Text$from_bytes(List_t bytes)
-{
- if (bytes.stride != sizeof(int8_t))
- List$compact(&bytes, sizeof(int8_t));
+public
+OptionalText_t Text$from_bytes(List_t bytes) {
+ if (bytes.stride != sizeof(int8_t)) List$compact(&bytes, sizeof(int8_t));
return Text$from_strn(bytes.data, (size_t)bytes.length);
}
-public List_t Text$lines(Text_t text)
-{
+public
+List_t Text$lines(Text_t text) {
List_t lines = {};
TextIter_t state = NEW_TEXT_ITER_STATE(text);
for (int64_t i = 0, line_start = 0; i < text.length; i++) {
int32_t grapheme = Text$get_grapheme_fast(&state, i);
if (grapheme == '\r' && Text$get_grapheme_fast(&state, i + 1) == '\n') { // CRLF
- Text_t line = Text$slice(text, I(line_start+1), I(i));
+ Text_t line = Text$slice(text, I(line_start + 1), I(i));
List$insert(&lines, &line, I_small(0), sizeof(Text_t));
i += 1; // skip one extra for CR
line_start = i + 1;
} else if (grapheme == '\n') { // newline
- Text_t line = Text$slice(text, I(line_start+1), I(i));
+ Text_t line = Text$slice(text, I(line_start + 1), I(i));
List$insert(&lines, &line, I_small(0), sizeof(Text_t));
line_start = i + 1;
- } else if (i == text.length-1 && line_start != i) { // last line
- Text_t line = Text$slice(text, I(line_start+1), I(i+1));
+ } else if (i == text.length - 1 && line_start != i) { // last line
+ Text_t line = Text$slice(text, I(line_start + 1), I(i + 1));
List$insert(&lines, &line, I_small(0), sizeof(Text_t));
}
}
@@ -1736,21 +1673,20 @@ typedef struct {
int64_t i;
} line_iter_state_t;
-static OptionalText_t next_line(line_iter_state_t *state)
-{
+static OptionalText_t next_line(line_iter_state_t *state) {
Text_t text = state->state.stack[0].text;
for (int64_t i = state->i; i < text.length; i++) {
int32_t grapheme = Text$get_grapheme_fast(&state->state, i);
if (grapheme == '\r' && Text$get_grapheme_fast(&state->state, i + 1) == '\n') { // CRLF
- Text_t line = Text$slice(text, I(state->i+1), I(i));
+ Text_t line = Text$slice(text, I(state->i + 1), I(i));
state->i = i + 2; // skip one extra for CR
return line;
} else if (grapheme == '\n') { // newline
- Text_t line = Text$slice(text, I(state->i+1), I(i));
+ Text_t line = Text$slice(text, I(state->i + 1), I(i));
state->i = i + 1;
return line;
- } else if (i == text.length-1 && state->i != i) { // last line
- Text_t line = Text$slice(text, I(state->i+1), I(i+1));
+ } else if (i == text.length - 1 && state->i != i) { // last line
+ Text_t line = Text$slice(text, I(state->i + 1), I(i + 1));
state->i = i + 1;
return line;
}
@@ -1758,81 +1694,75 @@ static OptionalText_t next_line(line_iter_state_t *state)
return NONE_TEXT;
}
-public Closure_t Text$by_line(Text_t text)
-{
+public
+Closure_t Text$by_line(Text_t text) {
return (Closure_t){
- .fn=(void*)next_line,
- .userdata=new(line_iter_state_t, .state=NEW_TEXT_ITER_STATE(text), .i=0),
+ .fn = (void *)next_line,
+ .userdata = new (line_iter_state_t, .state = NEW_TEXT_ITER_STATE(text), .i = 0),
};
}
-PUREFUNC public bool Text$is_none(const void *t, const TypeInfo_t *info)
-{
+PUREFUNC public bool Text$is_none(const void *t, const TypeInfo_t *info) {
(void)info;
- return ((Text_t*)t)->length < 0;
+ return ((Text_t *)t)->length < 0;
}
-public Int_t Text$memory_size(Text_t text)
-{
+public
+Int_t Text$memory_size(Text_t text) {
switch (text.tag) {
- case TEXT_ASCII:
- return Int$from_int64((int64_t)sizeof(Text_t) + (int64_t)sizeof(char[text.length]));
- case TEXT_GRAPHEMES:
- return Int$from_int64((int64_t)sizeof(Text_t) + (int64_t)sizeof(int32_t[text.length]));
+ case TEXT_ASCII: return Int$from_int64((int64_t)sizeof(Text_t) + (int64_t)sizeof(char[text.length]));
+ case TEXT_GRAPHEMES: return Int$from_int64((int64_t)sizeof(Text_t) + (int64_t)sizeof(int32_t[text.length]));
case TEXT_BLOB:
- return Int$from_int64((int64_t)sizeof(Text_t) + (int64_t)((void*)text.blob.bytes - (void*)text.blob.map) + (int64_t)sizeof(uint8_t[text.length]));
+ return Int$from_int64((int64_t)sizeof(Text_t) + (int64_t)((void *)text.blob.bytes - (void *)text.blob.map)
+ + (int64_t)sizeof(uint8_t[text.length]));
case TEXT_CONCAT:
- return Int$plus(
- Int$from_int64((int64_t)sizeof(Text_t)),
- Int$plus(Text$memory_size(*text.left), Text$memory_size(*text.right)));
+ return Int$plus(Int$from_int64((int64_t)sizeof(Text_t)),
+ Int$plus(Text$memory_size(*text.left), Text$memory_size(*text.right)));
default: errx(1, "Invalid text tag: %d", text.tag);
}
}
-public Text_t Text$layout(Text_t text)
-{
+public
+Text_t Text$layout(Text_t text) {
switch (text.tag) {
- case TEXT_ASCII:
- return Texts(Text("ASCII("), Int64$as_text((int64_t[1]){text.length}, false, NULL), Text(")"));
+ case TEXT_ASCII: return Texts(Text("ASCII("), Int64$as_text((int64_t[1]){text.length}, false, NULL), Text(")"));
case TEXT_GRAPHEMES:
return Texts(Text("Graphemes("), Int64$as_text((int64_t[1]){text.length}, false, NULL), Text(")"));
- case TEXT_BLOB:
- return Texts(Text("Blob("), Int64$as_text((int64_t[1]){text.length}, false, NULL), Text(")"));
+ case TEXT_BLOB: return Texts(Text("Blob("), Int64$as_text((int64_t[1]){text.length}, false, NULL), Text(")"));
case TEXT_CONCAT:
return Texts(Text("Concat("), Text$layout(*text.left), Text(", "), Text$layout(*text.right), Text(")"));
default: errx(1, "Invalid text tag: %d", text.tag);
}
}
-public void Text$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *info)
-{
+public
+void Text$serialize(const void *obj, FILE *out, Table_t *pointers, const TypeInfo_t *info) {
(void)info;
- const char *str = Text$as_c_string(*(Text_t*)obj);
+ const char *str = Text$as_c_string(*(Text_t *)obj);
int64_t len = (int64_t)strlen(str);
Int64$serialize(&len, out, pointers, &Int64$info);
fwrite(str, sizeof(char), (size_t)len, out);
}
-public void Text$deserialize(FILE *in, void *out, List_t *pointers, const TypeInfo_t *info)
-{
+public
+void Text$deserialize(FILE *in, void *out, List_t *pointers, const TypeInfo_t *info) {
(void)info;
int64_t len = 0;
Int64$deserialize(in, &len, pointers, &Int64$info);
- if (len < 0)
- fail("Cannot deserialize text with a negative length!");
- char *buf = GC_MALLOC_ATOMIC((size_t)len+1);
- if (fread(buf, sizeof(char), (size_t)len, in) != (size_t)len)
- fail("Not enough data in stream to deserialize");
- buf[len+1] = '\0';
- *(Text_t*)out = Text$from_strn(buf, (size_t)len);
-}
-
-public const TypeInfo_t Text$info = {
- .size=sizeof(Text_t),
- .align=__alignof__(Text_t),
- .tag=TextInfo,
- .TextInfo={.lang="Text"},
- .metamethods=Text$metamethods,
+ if (len < 0) fail("Cannot deserialize text with a negative length!");
+ char *buf = GC_MALLOC_ATOMIC((size_t)len + 1);
+ if (fread(buf, sizeof(char), (size_t)len, in) != (size_t)len) fail("Not enough data in stream to deserialize");
+ buf[len + 1] = '\0';
+ *(Text_t *)out = Text$from_strn(buf, (size_t)len);
+}
+
+public
+const TypeInfo_t Text$info = {
+ .size = sizeof(Text_t),
+ .align = __alignof__(Text_t),
+ .tag = TextInfo,
+ .TextInfo = {.lang = "Text"},
+ .metamethods = Text$metamethods,
};
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/stdlib/text.h b/src/stdlib/text.h
index cb3f1b90..6bedcb60 100644
--- a/src/stdlib/text.h
+++ b/src/stdlib/text.h
@@ -21,22 +21,20 @@ typedef struct {
int64_t stack_index;
} TextIter_t;
-#define NEW_TEXT_ITER_STATE(t) (TextIter_t){.stack={{t, 0}}, .stack_index=0}
+#define NEW_TEXT_ITER_STATE(t) (TextIter_t){.stack = {{t, 0}}, .stack_index = 0}
-#define Text(str) ((Text_t){.length=sizeof(str)-1, .tag=TEXT_ASCII, .ascii="" str})
+#define Text(str) ((Text_t){.length = sizeof(str) - 1, .tag = TEXT_ASCII, .ascii = "" str})
static inline Text_t Text_from_str_literal(const char *str) {
- return (Text_t){.length=strlen(str), .tag=TEXT_ASCII, .ascii=str};
+ return (Text_t){.length = strlen(str), .tag = TEXT_ASCII, .ascii = str};
}
-static inline Text_t Text_from_text(Text_t t) {
- return t;
-}
+static inline Text_t Text_from_text(Text_t t) { return t; }
-#define convert_to_text(x) _Generic(x, Text_t: Text_from_text, char*: Text$from_str, const char*: Text$from_str)(x)
+#define convert_to_text(x) _Generic(x, Text_t: Text_from_text, char *: Text$from_str, const char *: Text$from_str)(x)
Text_t Text$_concat(int n, Text_t items[n]);
-#define Text$concat(...) Text$_concat(sizeof((Text_t[]){__VA_ARGS__})/sizeof(Text_t), (Text_t[]){__VA_ARGS__})
+#define Text$concat(...) Text$_concat(sizeof((Text_t[]){__VA_ARGS__}) / sizeof(Text_t), (Text_t[]){__VA_ARGS__})
#define Texts(...) Text$concat(MAP_LIST(convert_to_text, __VA_ARGS__))
// int Text$print(FILE *stream, Text_t t);
Text_t Text$slice(Text_t text, Int_t first_int, Int_t last_int);
@@ -46,12 +44,12 @@ Text_t Text$reversed(Text_t text);
Text_t Text$cluster(Text_t text, Int_t index_int);
OptionalText_t Text$from_str(const char *str);
OptionalText_t Text$from_strn(const char *str, size_t len);
-PUREFUNC uint64_t Text$hash(const void *text, const TypeInfo_t*);
-PUREFUNC int32_t Text$compare(const void *va, const void *vb, const TypeInfo_t*);
-PUREFUNC bool Text$equal(const void *a, const void *b, const TypeInfo_t*);
+PUREFUNC uint64_t Text$hash(const void *text, const TypeInfo_t *);
+PUREFUNC int32_t Text$compare(const void *va, const void *vb, const TypeInfo_t *);
+PUREFUNC bool Text$equal(const void *a, const void *b, const TypeInfo_t *);
PUREFUNC bool Text$equal_values(Text_t a, Text_t b);
PUREFUNC bool Text$equal_ignoring_case(Text_t a, Text_t b, Text_t language);
-PUREFUNC bool Text$is_none(const void *t, const TypeInfo_t*);
+PUREFUNC bool Text$is_none(const void *t, const TypeInfo_t *);
Text_t Text$upper(Text_t text, Text_t language);
Text_t Text$lower(Text_t text, Text_t language);
Text_t Text$title(Text_t text, Text_t language);
@@ -92,8 +90,7 @@ Text_t Text$layout(Text_t text);
void Text$serialize(const void *obj, FILE *out, Table_t *, const TypeInfo_t *);
void Text$deserialize(FILE *in, void *out, List_t *, const TypeInfo_t *);
-MACROLIKE int32_t Text$get_grapheme(Text_t text, int64_t index)
-{
+MACROLIKE int32_t Text$get_grapheme(Text_t text, int64_t index) {
TextIter_t state = NEW_TEXT_ITER_STATE(text);
return Text$get_grapheme_fast(&state, index);
}
@@ -101,14 +98,15 @@ MACROLIKE int32_t Text$get_grapheme(Text_t text, int64_t index)
extern const TypeInfo_t Text$info;
extern Text_t EMPTY_TEXT;
-#define Text$metamethods { \
- .as_text=Text$as_text, \
- .hash=Text$hash, \
- .compare=Text$compare, \
- .equal=Text$equal, \
- .is_none=Text$is_none, \
- .serialize=Text$serialize, \
- .deserialize=Text$deserialize, \
-}
+#define Text$metamethods \
+ { \
+ .as_text = Text$as_text, \
+ .hash = Text$hash, \
+ .compare = Text$compare, \
+ .equal = Text$equal, \
+ .is_none = Text$is_none, \
+ .serialize = Text$serialize, \
+ .deserialize = Text$deserialize, \
+ }
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/stdlib/types.c b/src/stdlib/types.c
index 0f17cb21..e64195fe 100644
--- a/src/stdlib/types.c
+++ b/src/stdlib/types.c
@@ -3,24 +3,21 @@
#include <gc.h>
#include <sys/param.h>
-#include "util.h"
#include "text.h"
#include "types.h"
+#include "util.h"
-public Text_t Type$as_text(const void *typeinfo, bool colorize, const TypeInfo_t *type)
-{
+public
+Text_t Type$as_text(const void *typeinfo, bool colorize, const TypeInfo_t *type) {
if (!typeinfo) return Text("Type");
- if (colorize)
- return Text$concat(
- Text("\x1b[36;1m"),
- Text$from_str(type->TypeInfoInfo.type_str),
- Text("\x1b[m"));
- else
- return Text$from_str(type->TypeInfoInfo.type_str);
+ if (colorize) return Text$concat(Text("\x1b[36;1m"), Text$from_str(type->TypeInfoInfo.type_str), Text("\x1b[m"));
+ else return Text$from_str(type->TypeInfoInfo.type_str);
}
-public const TypeInfo_t Void$info = {.size=0, .align=0, .tag=StructInfo};
-public const TypeInfo_t Abort$info = {.size=0, .align=0, .tag=StructInfo};
+public
+const TypeInfo_t Void$info = {.size = 0, .align = 0, .tag = StructInfo};
+public
+const TypeInfo_t Abort$info = {.size = 0, .align = 0, .tag = StructInfo};
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/stdlib/types.h b/src/stdlib/types.h
index 60f1fcfd..a6509183 100644
--- a/src/stdlib/types.h
+++ b/src/stdlib/types.h
@@ -10,13 +10,13 @@
typedef struct TypeInfo_s TypeInfo_t;
-typedef void (*serialize_fn_t)(const void*, FILE*, Table_t*, const TypeInfo_t*);
-typedef void (*deserialize_fn_t)(FILE*, void*, List_t*, const TypeInfo_t*);
-typedef bool (*is_none_fn_t)(const void*, const TypeInfo_t*);
-typedef uint64_t (*hash_fn_t)(const void*, const TypeInfo_t*);
-typedef int32_t (*compare_fn_t)(const void*, const void*, const TypeInfo_t*);
-typedef bool (*equal_fn_t)(const void*, const void*, const TypeInfo_t*);
-typedef Text_t (*as_text_fn_t)(const void*, bool, const TypeInfo_t*);
+typedef void (*serialize_fn_t)(const void *, FILE *, Table_t *, const TypeInfo_t *);
+typedef void (*deserialize_fn_t)(FILE *, void *, List_t *, const TypeInfo_t *);
+typedef bool (*is_none_fn_t)(const void *, const TypeInfo_t *);
+typedef uint64_t (*hash_fn_t)(const void *, const TypeInfo_t *);
+typedef int32_t (*compare_fn_t)(const void *, const void *, const TypeInfo_t *);
+typedef bool (*equal_fn_t)(const void *, const void *, const TypeInfo_t *);
+typedef Text_t (*as_text_fn_t)(const void *, bool, const TypeInfo_t *);
typedef struct {
hash_fn_t hash;
@@ -36,11 +36,22 @@ typedef struct {
struct TypeInfo_s {
int64_t size, align;
metamethods_t metamethods;
- struct { // Anonymous tagged union for convenience
- enum { OpaqueInfo, StructInfo, EnumInfo, PointerInfo, TextInfo, ListInfo, TableInfo, FunctionInfo,
- OptionalInfo, TypeInfoInfo } tag;
+ struct { // Anonymous tagged union for convenience
+ enum {
+ OpaqueInfo,
+ StructInfo,
+ EnumInfo,
+ PointerInfo,
+ TextInfo,
+ ListInfo,
+ TableInfo,
+ FunctionInfo,
+ OptionalInfo,
+ TypeInfoInfo
+ } tag;
union {
- struct {} OpaqueInfo;
+ struct {
+ } OpaqueInfo;
struct {
const char *sigil;
const TypeInfo_t *pointed;
@@ -72,7 +83,7 @@ struct TypeInfo_s {
const char *name;
NamedType_t *fields;
int num_fields;
- bool is_secret:1, is_opaque:1;
+ bool is_secret : 1, is_opaque : 1;
} StructInfo;
};
};
@@ -84,18 +95,22 @@ extern const TypeInfo_t Abort$info;
Text_t Type$as_text(const void *typeinfo, bool colorize, const TypeInfo_t *type);
-#define Type$info(typestr) &((TypeInfo_t){.size=sizeof(TypeInfo_t), .align=__alignof__(TypeInfo_t), \
- .tag=TypeInfoInfo, .TypeInfoInfo.type_str=typestr, \
- .metamethods={.serialize=cannot_serialize, .deserialize=cannot_deserialize, .as_text=Type$as_text}})
+#define Type$info(typestr) \
+ &((TypeInfo_t){ \
+ .size = sizeof(TypeInfo_t), \
+ .align = __alignof__(TypeInfo_t), \
+ .tag = TypeInfoInfo, \
+ .TypeInfoInfo.type_str = typestr, \
+ .metamethods = {.serialize = cannot_serialize, .deserialize = cannot_deserialize, .as_text = Type$as_text}})
-#define DEFINE_OPTIONAL_TYPE(t, unpadded_size, name) \
- typedef struct { \
- union { \
- t value; \
- struct { \
- char _padding[unpadded_size]; \
- Bool_t is_none; \
- }; \
- }; \
+#define DEFINE_OPTIONAL_TYPE(t, unpadded_size, name) \
+ typedef struct { \
+ union { \
+ t value; \
+ struct { \
+ char _padding[unpadded_size]; \
+ Bool_t is_none; \
+ }; \
+ }; \
} name
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/stdlib/util.h b/src/stdlib/util.h
index 3b00e6e9..819cecd9 100644
--- a/src/stdlib/util.h
+++ b/src/stdlib/util.h
@@ -3,38 +3,56 @@
// Built-in utility functions
#include <assert.h>
+#include <err.h>
#include <gc.h>
#include <stdbool.h>
#include <string.h>
-#include <err.h>
#define streq(a, b) (((a) == NULL && (b) == NULL) || (((a) == NULL) == ((b) == NULL) && strcmp(a, b) == 0))
#define starts_with(line, prefix) (strncmp(line, prefix, strlen(prefix)) == 0)
-#define ends_with(line, suffix) (strlen(line) >= strlen(suffix) && strcmp(line + strlen(line) - strlen(suffix), suffix) == 0)
-#define new(t, ...) ((t*)memcpy(GC_MALLOC(sizeof(t)), &(t){__VA_ARGS__}, sizeof(t)))
-#define heap(x) (__typeof(x)*)memcpy(GC_MALLOC(sizeof(x)), (__typeof(x)[1]){x}, sizeof(x))
-#define stack(x) (__typeof(x)*)((__typeof(x)[1]){x})
-#define check_initialized(var, init_var, name) *({ if (!init_var) fail("The variable " name " is being accessed before it has been initialized!"); \
- &var; })
+#define ends_with(line, suffix) \
+ (strlen(line) >= strlen(suffix) && strcmp(line + strlen(line) - strlen(suffix), suffix) == 0)
+#define new(t, ...) ((t *)memcpy(GC_MALLOC(sizeof(t)), &(t){__VA_ARGS__}, sizeof(t)))
+#define heap(x) (__typeof(x) *)memcpy(GC_MALLOC(sizeof(x)), (__typeof(x)[1]){x}, sizeof(x))
+#define stack(x) (__typeof(x) *)((__typeof(x)[1]){x})
+#define check_initialized(var, init_var, name) \
+ *({ \
+ if (!init_var) fail("The variable " name " is being accessed before it has been initialized!"); \
+ &var; \
+ })
-#define IF_DECLARE(decl, expr, block) if (({ decl; expr ? ({ block; 1; }) : 0; })) {}
+#define IF_DECLARE(decl, expr, block) \
+ if (({ \
+ decl; \
+ expr ? ({ \
+ block; \
+ 1; \
+ }) \
+ : 0; \
+ })) { \
+ }
-#define WHEN(type, subj, var, body) { type var = subj; switch (var.$tag) body }
+#define WHEN(type, subj, var, body) \
+ { \
+ type var = subj; \
+ switch (var.$tag) \
+ body \
+ }
#ifndef public
-#define public __attribute__ ((visibility ("default")))
+#define public __attribute__((visibility("default")))
#endif
#ifndef PUREFUNC
-#define PUREFUNC __attribute__ ((pure))
+#define PUREFUNC __attribute__((pure))
#endif
#ifndef CONSTFUNC
-#define CONSTFUNC __attribute__ ((const))
+#define CONSTFUNC __attribute__((const))
#endif
#ifndef INLINE
-#define INLINE inline __attribute__ ((always_inline))
+#define INLINE inline __attribute__((always_inline))
#endif
#ifndef likely
diff --git a/src/structs.c b/src/structs.c
index 0bcb8a08..9be38d1f 100644
--- a/src/structs.c
+++ b/src/structs.c
@@ -5,31 +5,33 @@
#include "compile.h"
#include "environment.h"
#include "naming.h"
-#include "stdlib/text.h"
#include "stdlib/tables.h"
+#include "stdlib/text.h"
#include "typecheck.h"
-Text_t compile_struct_typeinfo(env_t *env, type_t *t, const char *name, arg_ast_t *fields, bool is_secret, bool is_opaque)
-{
+Text_t compile_struct_typeinfo(env_t *env, type_t *t, const char *name, arg_ast_t *fields, bool is_secret,
+ bool is_opaque) {
Text_t typeinfo_name = namespace_name(env, env->namespace, Texts(name, "$$info"));
- Text_t type_code = Match(t, StructType)->external ?
- Text$from_str(name) : Texts("struct ", namespace_name(env, env->namespace, Texts(name, "$$struct")));
+ Text_t type_code = Match(t, StructType)->external
+ ? Text$from_str(name)
+ : Texts("struct ", namespace_name(env, env->namespace, Texts(name, "$$struct")));
int num_fields = 0;
for (arg_ast_t *f = fields; f; f = f->next)
num_fields += 1;
const char *short_name = name;
- if (strchr(short_name, '$'))
- short_name = strrchr(short_name, '$') + 1;
+ if (strchr(short_name, '$')) short_name = strrchr(short_name, '$') + 1;
const char *metamethods = is_packed_data(t) ? "PackedData$metamethods" : "Struct$metamethods";
- Text_t typeinfo = Texts("public const TypeInfo_t ", typeinfo_name,
- " = {.size=sizeof(", type_code, "), .align=__alignof__(", type_code, "), "
- ".metamethods=", metamethods, ", "
- ".tag=StructInfo, .StructInfo.name=\"", short_name, "\"",
- is_secret ? Text(", .StructInfo.is_secret=true") : EMPTY_TEXT,
- is_opaque ? Text(", .StructInfo.is_opaque=true") : EMPTY_TEXT,
- ", .StructInfo.num_fields=", String(num_fields));
+ Text_t typeinfo = Texts(
+ "public const TypeInfo_t ", typeinfo_name, " = {.size=sizeof(", type_code, "), .align=__alignof__(", type_code,
+ "), "
+ ".metamethods=",
+ metamethods,
+ ", "
+ ".tag=StructInfo, .StructInfo.name=\"",
+ short_name, "\"", is_secret ? Text(", .StructInfo.is_secret=true") : EMPTY_TEXT,
+ is_opaque ? Text(", .StructInfo.is_opaque=true") : EMPTY_TEXT, ", .StructInfo.num_fields=", String(num_fields));
if (fields) {
typeinfo = Texts(typeinfo, ", .StructInfo.fields=(NamedType_t[", String(num_fields), "]){");
for (arg_ast_t *f = fields; f; f = f->next) {
@@ -42,12 +44,12 @@ Text_t compile_struct_typeinfo(env_t *env, type_t *t, const char *name, arg_ast_
return Texts(typeinfo, "};\n");
}
-Text_t compile_struct_header(env_t *env, ast_t *ast)
-{
+Text_t compile_struct_header(env_t *env, ast_t *ast) {
DeclareMatch(def, ast, StructDef);
Text_t typeinfo_name = namespace_name(env, env->namespace, Texts(def->name, "$$info"));
- Text_t type_code = def->external ? Text$from_str(def->name)
- : Texts("struct ", namespace_name(env, env->namespace, Texts(def->name, "$$struct")));
+ Text_t type_code = def->external
+ ? Text$from_str(def->name)
+ : Texts("struct ", namespace_name(env, env->namespace, Texts(def->name, "$$struct")));
Text_t fields = EMPTY_TEXT;
for (arg_ast_t *field = def->fields; field; field = field->next) {
@@ -65,12 +67,13 @@ Text_t compile_struct_header(env_t *env, ast_t *ast)
Text_t struct_code = def->external ? EMPTY_TEXT : Texts(type_code, " {\n", fields, "};\n");
type_t *t = Table$str_get(*env->types, def->name);
- Text_t unpadded_size = def->opaque ? Texts("sizeof(", type_code, ")") : Text$from_str(String((int64_t)unpadded_struct_size(t)));
+ Text_t unpadded_size =
+ def->opaque ? Texts("sizeof(", type_code, ")") : Text$from_str(String((int64_t)unpadded_struct_size(t)));
Text_t typeinfo_code = Texts("extern const TypeInfo_t ", typeinfo_name, ";\n");
Text_t optional_code = EMPTY_TEXT;
if (!def->opaque) {
optional_code = Texts("DEFINE_OPTIONAL_TYPE(", compile_type(t), ", ", unpadded_size, ", ",
- namespace_name(env, env->namespace, Texts("$Optional", def->name, "$$type")), ");\n");
+ namespace_name(env, env->namespace, Texts("$Optional", def->name, "$$type")), ");\n");
}
return Texts(struct_code, optional_code, typeinfo_code);
}
diff --git a/src/structs.h b/src/structs.h
index d5337626..9a9d08e5 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -5,7 +5,8 @@
#include "ast.h"
#include "environment.h"
-Text_t compile_struct_typeinfo(env_t *env, type_t *t, const char *name, arg_ast_t *fields, bool is_secret, bool is_opaque);
+Text_t compile_struct_typeinfo(env_t *env, type_t *t, const char *name, arg_ast_t *fields, bool is_secret,
+ bool is_opaque);
Text_t compile_struct_header(env_t *env, ast_t *ast);
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/tomo.c b/src/tomo.c
index 1aa16581..02a611d4 100644
--- a/src/tomo.c
+++ b/src/tomo.c
@@ -13,9 +13,9 @@
#endif
#include "ast.h"
-#include "config.h"
#include "changes.md.h"
#include "compile.h"
+#include "config.h"
#include "modules.h"
#include "naming.h"
#include "parse.h"
@@ -33,8 +33,18 @@
#include "stdlib/text.h"
#include "types.h"
-#define run_cmd(...) ({ const char *_cmd = String(__VA_ARGS__); if (verbose) print("\033[34;1m", _cmd, "\033[m"); popen(_cmd, "w"); })
-#define xsystem(...) ({ int _status = system(String(__VA_ARGS__)); if (!WIFEXITED(_status) || WEXITSTATUS(_status) != 0) errx(1, "Failed to run command: %s", String(__VA_ARGS__)); })
+#define run_cmd(...) \
+ ({ \
+ const char *_cmd = String(__VA_ARGS__); \
+ if (verbose) print("\033[34;1m", _cmd, "\033[m"); \
+ popen(_cmd, "w"); \
+ })
+#define xsystem(...) \
+ ({ \
+ int _status = system(String(__VA_ARGS__)); \
+ if (!WIFEXITED(_status) || WEXITSTATUS(_status) != 0) \
+ errx(1, "Failed to run command: %s", String(__VA_ARGS__)); \
+ })
#define list_text(list) Text$join(Text(" "), list)
#define whisper(...) print("\033[2m", __VA_ARGS__, "\033[m")
@@ -48,7 +58,7 @@ static const char *paths_str(List_t paths) {
Text_t result = EMPTY_TEXT;
for (int64_t i = 0; i < paths.length; i++) {
if (i > 0) result = Texts(result, Text(" "));
- result = Texts(result, Path$as_text((Path_t*)(paths.data + i*paths.stride), false, &Path$info));
+ result = Texts(result, Path$as_text((Path_t *)(paths.data + i * paths.stride), false, &Path$info));
}
return Text$as_c_string(result);
}
@@ -59,50 +69,39 @@ static const char *paths_str(List_t paths) {
#define SHARED_SUFFIX ".so"
#endif
-static OptionalList_t files = NONE_LIST,
- args = NONE_LIST,
- uninstall = NONE_LIST,
- libraries = NONE_LIST;
-static OptionalBool_t verbose = false,
- quiet = false,
- show_version = false,
- show_parse_tree = false,
- show_prefix = false,
- stop_at_transpile = false,
- stop_at_obj_compilation = false,
- compile_exe = false,
- should_install = false,
- clean_build = false,
- source_mapping = true,
+static OptionalList_t files = NONE_LIST, args = NONE_LIST, uninstall = NONE_LIST, libraries = NONE_LIST;
+static OptionalBool_t verbose = false, quiet = false, show_version = false, show_parse_tree = false,
+ show_prefix = false, stop_at_transpile = false, stop_at_obj_compilation = false,
+ compile_exe = false, should_install = false, clean_build = false, source_mapping = true,
show_changelog = false;
-static OptionalText_t
- show_codegen = NONE_TEXT,
- cflags = Text("-Werror -fdollars-in-identifiers -std=c2x -Wno-trigraphs "
- " -ffunction-sections -fdata-sections"
- " -fno-signed-zeros -fno-finite-math-only "
- " -D_XOPEN_SOURCE -D_DEFAULT_SOURCE -fPIC -ggdb"
+static OptionalText_t show_codegen = NONE_TEXT,
+ cflags = Text("-Werror -fdollars-in-identifiers -std=c2x -Wno-trigraphs "
+ " -ffunction-sections -fdata-sections"
+ " -fno-signed-zeros -fno-finite-math-only "
+ " -D_XOPEN_SOURCE -D_DEFAULT_SOURCE -fPIC -ggdb"
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
- " -D_BSD_SOURCE"
+ " -D_BSD_SOURCE"
#endif
- " -DGC_THREADS"
- " -I'" TOMO_PREFIX "/include' -I'" TOMO_PREFIX "/share/tomo_"TOMO_VERSION"/installed' -I/usr/local/include"),
- ldlibs = Text("-lgc -lm -lgmp -lunistring -ltomo_"TOMO_VERSION),
- ldflags = Text("-Wl,-rpath,'"TOMO_PREFIX"/lib',-rpath,/usr/local/lib"
- " -L/usr/local/lib"),
- optimization = Text("2"),
- cc = Text(DEFAULT_C_COMPILER);
+ " -DGC_THREADS"
+ " -I'" TOMO_PREFIX "/include' -I'" TOMO_PREFIX "/share/tomo_" TOMO_VERSION
+ "/installed' -I/usr/local/include"),
+ ldlibs = Text("-lgc -lm -lgmp -lunistring -ltomo_" TOMO_VERSION),
+ ldflags = Text("-Wl,-rpath,'" TOMO_PREFIX "/lib',-rpath,/usr/local/lib"
+ " -L/usr/local/lib"),
+ optimization = Text("2"), cc = Text(DEFAULT_C_COMPILER);
static Text_t config_summary,
- // This will be either "" or "sudo -u <user>" or "doas -u <user>"
- // to allow a command to put stuff into TOMO_PREFIX as the owner
- // of that directory.
- as_owner = Text("");
+ // This will be either "" or "sudo -u <user>" or "doas -u <user>"
+ // to allow a command to put stuff into TOMO_PREFIX as the owner
+ // of that directory.
+ as_owner = Text("");
static void transpile_header(env_t *base_env, Path_t path);
static void transpile_code(env_t *base_env, Path_t path);
static void compile_object_file(Path_t path);
-static Path_t compile_executable(env_t *base_env, Path_t path, Path_t exe_path, List_t object_files, List_t extra_ldlibs);
+static Path_t compile_executable(env_t *base_env, Path_t path, Path_t exe_path, List_t object_files,
+ List_t extra_ldlibs);
static void build_file_dependency_graph(Path_t path, Table_t *to_compile, Table_t *to_link);
static void build_library(Path_t lib_dir);
static void install_library(Path_t lib_dir);
@@ -114,25 +113,22 @@ static void wait_for_child_success(pid_t child);
static bool is_config_outdated(Path_t path);
typedef struct {
- bool h:1, c:1, o:1;
+ bool h : 1, c : 1, o : 1;
} staleness_t;
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstack-protector"
#endif
-int main(int argc, char *argv[])
-{
+int main(int argc, char *argv[]) {
#ifdef __linux__
// Get the file modification time of the compiler, so we
// can recompile files after changing the compiler:
char compiler_path[PATH_MAX];
ssize_t count = readlink("/proc/self/exe", compiler_path, PATH_MAX);
- if (count == -1)
- err(1, "Could not find age of compiler");
+ if (count == -1) err(1, "Could not find age of compiler");
compiler_path[count] = '\0';
- if (stat(compiler_path, &compiler_stat) != 0)
- err(1, "Could not find age of compiler");
+ if (stat(compiler_path, &compiler_stat) != 0) err(1, "Could not find age of compiler");
#endif
#ifdef __OpenBSD__
@@ -140,31 +136,32 @@ int main(int argc, char *argv[])
#endif
USE_COLOR = getenv("COLOR") ? strcmp(getenv("COLOR"), "1") == 0 : isatty(STDOUT_FILENO);
- if (getenv("NO_COLOR") && getenv("NO_COLOR")[0] != '\0')
- USE_COLOR = false;
+ if (getenv("NO_COLOR") && getenv("NO_COLOR")[0] != '\0') USE_COLOR = false;
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
arc4random_buf(TOMO_HASH_KEY, sizeof(TOMO_HASH_KEY));
#elif defined(__linux__)
assert(getrandom(TOMO_HASH_KEY, sizeof(TOMO_HASH_KEY), 0) == sizeof(TOMO_HASH_KEY));
#else
- #error "Unsupported platform for secure random number generation"
+#error "Unsupported platform for secure random number generation"
#endif
// Set up environment variables:
const char *PATH = getenv("PATH");
- setenv("PATH", PATH ? String(TOMO_PREFIX"/bin:", PATH) : TOMO_PREFIX"/bin", 1);
+ setenv("PATH", PATH ? String(TOMO_PREFIX "/bin:", PATH) : TOMO_PREFIX "/bin", 1);
const char *LD_LIBRARY_PATH = getenv("LD_LIBRARY_PATH");
- setenv("LD_LIBRARY_PATH", LD_LIBRARY_PATH ? String(TOMO_PREFIX"/lib:", LD_LIBRARY_PATH) : TOMO_PREFIX"/lib", 1);
+ setenv("LD_LIBRARY_PATH", LD_LIBRARY_PATH ? String(TOMO_PREFIX "/lib:", LD_LIBRARY_PATH) : TOMO_PREFIX "/lib", 1);
const char *LIBRARY_PATH = getenv("LIBRARY_PATH");
- setenv("LIBRARY_PATH", LIBRARY_PATH ? String(TOMO_PREFIX"/lib:", LIBRARY_PATH) : TOMO_PREFIX"/lib", 1);
+ setenv("LIBRARY_PATH", LIBRARY_PATH ? String(TOMO_PREFIX "/lib:", LIBRARY_PATH) : TOMO_PREFIX "/lib", 1);
const char *C_INCLUDE_PATH = getenv("C_INCLUDE_PATH");
- setenv("C_INCLUDE_PATH", C_INCLUDE_PATH ? String(TOMO_PREFIX"/include:", C_INCLUDE_PATH) : TOMO_PREFIX"/include", 1);
+ setenv("C_INCLUDE_PATH", C_INCLUDE_PATH ? String(TOMO_PREFIX "/include:", C_INCLUDE_PATH) : TOMO_PREFIX "/include",
+ 1);
// Run a tool:
if ((streq(argv[1], "-r") || streq(argv[1], "--run")) && argc >= 3) {
if (strcspn(argv[2], "/;$") == strlen(argv[2])) {
- const char *program = String("'"TOMO_PREFIX"'/share/tomo_"TOMO_VERSION"/installed/", argv[2], "/", argv[2]);
+ const char *program =
+ String("'" TOMO_PREFIX "'/share/tomo_" TOMO_VERSION "/installed/", argv[2], "/", argv[2]);
execv(program, &argv[2]);
}
print_err("This is not an installed tomo program: ", argv[2]);
@@ -183,43 +180,25 @@ int main(int argc, char *argv[])
" --parse|-p: show parse tree\n"
" --install|-I: install the executable or library\n"
" --optimization|-O <level>: set optimization level\n"
- " --run|-r: run a program from " TOMO_PREFIX "/share/tomo_"TOMO_VERSION"/installed\n"
- );
+ " --run|-r: run a program from " TOMO_PREFIX "/share/tomo_" TOMO_VERSION "/installed\n");
Text_t help = Texts(Text("\x1b[1mtomo\x1b[m: a compiler for the Tomo programming language"), Text("\n\n"), usage);
tomo_parse_args(
- argc, argv, usage, help, TOMO_VERSION,
- {"files", true, List$info(&Path$info), &files},
- {"args", true, List$info(&Text$info), &args},
- {"verbose", false, &Bool$info, &verbose},
- {"v", false, &Bool$info, &verbose},
- {"version", false, &Bool$info, &show_version},
- {"parse", false, &Bool$info, &show_parse_tree},
- {"p", false, &Bool$info, &show_parse_tree},
- {"prefix", false, &Bool$info, &show_prefix},
- {"quiet", false, &Bool$info, &quiet},
- {"q", false, &Bool$info, &quiet},
- {"transpile", false, &Bool$info, &stop_at_transpile},
- {"t", false, &Bool$info, &stop_at_transpile},
- {"compile-obj", false, &Bool$info, &stop_at_obj_compilation},
- {"c", false, &Bool$info, &stop_at_obj_compilation},
- {"compile-exe", false, &Bool$info, &compile_exe},
- {"e", false, &Bool$info, &compile_exe},
- {"uninstall", false, List$info(&Text$info), &uninstall},
- {"u", false, List$info(&Text$info), &uninstall},
- {"library", false, List$info(&Path$info), &libraries},
- {"L", false, List$info(&Path$info), &libraries},
- {"show-codegen", false, &Text$info, &show_codegen},
- {"C", false, &Text$info, &show_codegen},
- {"install", false, &Bool$info, &should_install},
- {"I", false, &Bool$info, &should_install},
- {"optimization", false, &Text$info, &optimization},
- {"O", false, &Text$info, &optimization},
- {"force-rebuild", false, &Bool$info, &clean_build},
- {"f", false, &Bool$info, &clean_build},
- {"source-mapping", false, &Bool$info, &source_mapping},
- {"m", false, &Bool$info, &source_mapping},
- {"changelog", false, &Bool$info, &show_changelog},
- );
+ argc, argv, usage, help, TOMO_VERSION, {"files", true, List$info(&Path$info), &files},
+ {"args", true, List$info(&Text$info), &args}, {"verbose", false, &Bool$info, &verbose},
+ {"v", false, &Bool$info, &verbose}, {"version", false, &Bool$info, &show_version},
+ {"parse", false, &Bool$info, &show_parse_tree}, {"p", false, &Bool$info, &show_parse_tree},
+ {"prefix", false, &Bool$info, &show_prefix}, {"quiet", false, &Bool$info, &quiet},
+ {"q", false, &Bool$info, &quiet}, {"transpile", false, &Bool$info, &stop_at_transpile},
+ {"t", false, &Bool$info, &stop_at_transpile}, {"compile-obj", false, &Bool$info, &stop_at_obj_compilation},
+ {"c", false, &Bool$info, &stop_at_obj_compilation}, {"compile-exe", false, &Bool$info, &compile_exe},
+ {"e", false, &Bool$info, &compile_exe}, {"uninstall", false, List$info(&Text$info), &uninstall},
+ {"u", false, List$info(&Text$info), &uninstall}, {"library", false, List$info(&Path$info), &libraries},
+ {"L", false, List$info(&Path$info), &libraries}, {"show-codegen", false, &Text$info, &show_codegen},
+ {"C", false, &Text$info, &show_codegen}, {"install", false, &Bool$info, &should_install},
+ {"I", false, &Bool$info, &should_install}, {"optimization", false, &Text$info, &optimization},
+ {"O", false, &Text$info, &optimization}, {"force-rebuild", false, &Bool$info, &clean_build},
+ {"f", false, &Bool$info, &clean_build}, {"source-mapping", false, &Bool$info, &source_mapping},
+ {"m", false, &Bool$info, &source_mapping}, {"changelog", false, &Bool$info, &show_changelog}, );
if (show_prefix) {
print(TOMO_PREFIX);
@@ -227,15 +206,13 @@ int main(int argc, char *argv[])
}
if (show_changelog) {
- print_inline(string_slice((const char*)CHANGES_md, CHANGES_md_len));
+ print_inline(string_slice((const char *)CHANGES_md, CHANGES_md_len));
return 0;
}
if (show_version) {
- if (verbose)
- print(TOMO_VERSION, " ", GIT_VERSION);
- else
- print(TOMO_VERSION);
+ if (verbose) print(TOMO_VERSION, " ", GIT_VERSION);
+ else print(TOMO_VERSION);
return 0;
}
@@ -256,25 +233,25 @@ int main(int argc, char *argv[])
#endif
if (show_codegen.length > 0 && Text$equal_values(show_codegen, Text("pretty")))
- show_codegen = Text("{ sed '/^#line/d;/^$/d' | indent -o /dev/stdout | bat -l c -P; }");
+ show_codegen = Text("{ sed '/^#line/d;/^$/d' | clang-format | bat -l c -P; }");
config_summary = Text$from_str(String(cc, " ", cflags, " -O", optimization));
Text_t owner = Path$owner(Path$from_str(TOMO_PREFIX), true);
Text_t user = Text$from_str(getenv("USER"));
if (!Text$equal_values(user, owner)) {
- as_owner = Texts(Text(SUDO" -u "), owner, Text(" "));
+ as_owner = Texts(Text(SUDO " -u "), owner, Text(" "));
}
for (int64_t i = 0; i < uninstall.length; i++) {
- Text_t *u = (Text_t*)(uninstall.data + i*uninstall.stride);
- xsystem(as_owner, "rm -rvf '"TOMO_PREFIX"'/share/tomo_"TOMO_VERSION"/installed/", *u);
+ Text_t *u = (Text_t *)(uninstall.data + i * uninstall.stride);
+ xsystem(as_owner, "rm -rvf '" TOMO_PREFIX "'/share/tomo_" TOMO_VERSION "/installed/", *u);
print("Uninstalled ", *u);
}
Path_t cwd = Path$current_dir();
for (int64_t i = 0; i < libraries.length; i++) {
- Path_t *lib = (Path_t*)(libraries.data + i*libraries.stride);
+ Path_t *lib = (Path_t *)(libraries.data + i * libraries.stride);
*lib = Path$resolved(*lib, cwd);
// Fork a child process to build the library to prevent cross-contamination
// of side effects when building one library from affecting another library.
@@ -282,8 +259,7 @@ int main(int argc, char *argv[])
pid_t child = fork();
if (child == 0) {
build_library(*lib);
- if (should_install)
- install_library(*lib);
+ if (should_install) install_library(*lib);
_exit(0);
}
wait_for_child_success(child);
@@ -301,22 +277,19 @@ int main(int argc, char *argv[])
// Convert `foo` to `foo/foo.tm` and resolve all paths to absolute paths:
Path_t cur_dir = Path$current_dir();
for (int64_t i = 0; i < files.length; i++) {
- Path_t *path = (Path_t*)(files.data + i*files.stride);
- if (Path$is_directory(*path, true))
- *path = Path$child(*path, Texts(Path$base_name(*path), Text(".tm")));
+ Path_t *path = (Path_t *)(files.data + i * files.stride);
+ if (Path$is_directory(*path, true)) *path = Path$child(*path, Texts(Path$base_name(*path), Text(".tm")));
*path = Path$resolved(*path, cur_dir);
- if (!Path$exists(*path))
- fail("File not found: ", *path);
+ if (!Path$exists(*path)) fail("File not found: ", *path);
}
- if (files.length < 1)
- print_err("No file specified!");
+ if (files.length < 1) print_err("No file specified!");
quiet = !verbose;
for (int64_t i = 0; i < files.length; i++) {
- Path_t path = *(Path_t*)(files.data + i*files.stride);
+ Path_t path = *(Path_t *)(files.data + i * files.stride);
if (show_parse_tree) {
ast_t *ast = parse_file(Path$as_c_string(path), NULL);
print(ast_to_sexp_str(ast));
@@ -324,23 +297,21 @@ int main(int argc, char *argv[])
}
Path_t exe_path = compile_exe ? Path$with_extension(path, Text(""), true)
- : build_file(Path$with_extension(path, Text(""), true), "");
+ : build_file(Path$with_extension(path, Text(""), true), "");
pid_t child = fork();
if (child == 0) {
env_t *env = global_env(source_mapping);
- List_t object_files = {},
- extra_ldlibs = {};
+ List_t object_files = {}, extra_ldlibs = {};
compile_files(env, files, &object_files, &extra_ldlibs);
compile_executable(env, path, exe_path, object_files, extra_ldlibs);
- if (compile_exe)
- _exit(0);
+ if (compile_exe) _exit(0);
char *prog_args[1 + args.length + 1];
- prog_args[0] = (char*)Path$as_c_string(exe_path);
+ prog_args[0] = (char *)Path$as_c_string(exe_path);
for (int64_t j = 0; j < args.length; j++)
- prog_args[j + 1] = Text$as_c_string(*(Text_t*)(args.data + j*args.stride));
+ prog_args[j + 1] = Text$as_c_string(*(Text_t *)(args.data + j * args.stride));
prog_args[1 + args.length] = NULL;
execv(prog_args[0], prog_args);
print_err("Could not execute program: ", prog_args[0]);
@@ -351,9 +322,9 @@ int main(int argc, char *argv[])
if (compile_exe && should_install) {
for (int64_t i = 0; i < files.length; i++) {
- Path_t path = *(Path_t*)(files.data + i*files.stride);
+ Path_t path = *(Path_t *)(files.data + i * files.stride);
Path_t exe = Path$with_extension(path, Text(""), true);
- xsystem(as_owner, "cp -v '", exe, "' '"TOMO_PREFIX"'/bin/");
+ xsystem(as_owner, "cp -v '", exe, "' '" TOMO_PREFIX "'/bin/");
}
}
return 0;
@@ -362,14 +333,11 @@ int main(int argc, char *argv[])
#pragma GCC diagnostic pop
#endif
-void wait_for_child_success(pid_t child)
-{
+void wait_for_child_success(pid_t child) {
int status;
while (waitpid(child, &status, 0) < 0 && errno == EINTR) {
- if (WIFEXITED(status) || WIFSIGNALED(status))
- break;
- else if (WIFSTOPPED(status))
- kill(child, SIGCONT);
+ if (WIFEXITED(status) || WIFSIGNALED(status)) break;
+ else if (WIFSTOPPED(status)) kill(child, SIGCONT);
}
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
@@ -377,18 +345,15 @@ void wait_for_child_success(pid_t child)
}
}
-Path_t build_file(Path_t path, const char *extension)
-{
+Path_t build_file(Path_t path, const char *extension) {
Path_t build_dir = Path$sibling(path, Text(".build"));
if (mkdir(Path$as_c_string(build_dir), 0755) != 0) {
- if (!Path$is_directory(build_dir, true))
- err(1, "Could not make .build directory");
+ if (!Path$is_directory(build_dir, true)) err(1, "Could not make .build directory");
}
return Path$child(build_dir, Texts(Path$base_name(path), Text$from_str(extension)));
}
-static const char *get_version(Path_t lib_dir)
-{
+static const char *get_version(Path_t lib_dir) {
Path_t changes_file = Path$child(lib_dir, Text("CHANGES.md"));
OptionalText_t changes = Path$read(changes_file);
if (changes.length <= 0) {
@@ -401,22 +366,16 @@ static const char *get_version(Path_t lib_dir)
return String(string_slice(version_line + 4, strcspn(version_line + 4, "\r\n")));
}
-static Text_t get_version_suffix(Path_t lib_dir)
-{
- return Texts(Text("_"), Text$from_str(get_version(lib_dir)));
-}
+static Text_t get_version_suffix(Path_t lib_dir) { return Texts(Text("_"), Text$from_str(get_version(lib_dir))); }
-void build_library(Path_t lib_dir)
-{
+void build_library(Path_t lib_dir) {
lib_dir = Path$resolved(lib_dir, Path$current_dir());
- if (!Path$is_directory(lib_dir, true))
- print_err("Not a valid directory: ", lib_dir);
+ if (!Path$is_directory(lib_dir, true)) print_err("Not a valid directory: ", lib_dir);
Text_t lib_dir_name = Path$base_name(lib_dir);
List_t tm_files = Path$glob(Path$child(lib_dir, Text("[!._0-9]*.tm")));
env_t *env = fresh_scope(global_env(source_mapping));
- List_t object_files = {},
- extra_ldlibs = {};
+ List_t object_files = {}, extra_ldlibs = {};
compile_files(env, tm_files, &object_files, &extra_ldlibs);
@@ -429,27 +388,27 @@ void build_library(Path_t lib_dir)
FILE *prog = run_cmd(cc, " -O", optimization, " ", cflags, " ", ldflags, " ", ldlibs, " ", list_text(extra_ldlibs),
#ifdef __APPLE__
- " -Wl,-install_name,@rpath/'lib", lib_dir_name, version_suffix, SHARED_SUFFIX, "'"
+ " -Wl,-install_name,@rpath/'lib", lib_dir_name, version_suffix, SHARED_SUFFIX,
+ "'"
#else
- " -Wl,-soname,'lib", lib_dir_name, version_suffix, SHARED_SUFFIX, "'"
+ " -Wl,-soname,'lib", lib_dir_name, version_suffix, SHARED_SUFFIX,
+ "'"
#endif
- " -shared ", paths_str(object_files), " -o '", shared_lib, "'");
+ " -shared ",
+ paths_str(object_files), " -o '", shared_lib, "'");
- if (!prog)
- print_err("Failed to run C compiler: ", cc);
+ if (!prog) print_err("Failed to run C compiler: ", cc);
int status = pclose(prog);
- if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
- exit(EXIT_FAILURE);
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) exit(EXIT_FAILURE);
- if (!quiet)
- print("Compiled library:\t", shared_lib);
+ if (!quiet) print("Compiled library:\t", shared_lib);
}
-void install_library(Path_t lib_dir)
-{
+void install_library(Path_t lib_dir) {
Text_t lib_dir_name = Path$base_name(lib_dir);
Text_t version_suffix = get_version_suffix(lib_dir);
- Path_t dest = Path$child(Path$from_str(TOMO_PREFIX"/share/tomo_"TOMO_VERSION"/installed"), Texts(lib_dir_name, version_suffix));
+ Path_t dest = Path$child(Path$from_str(TOMO_PREFIX "/share/tomo_" TOMO_VERSION "/installed"),
+ Texts(lib_dir_name, version_suffix));
if (!Path$equal_values(lib_dir, dest)) {
if (verbose) whisper("Clearing out any pre-existing version of ", lib_dir_name);
xsystem(as_owner, "rm -rf '", dest, "'");
@@ -461,25 +420,26 @@ void install_library(Path_t lib_dir)
// If we have `debugedit` on this system, use it to remap the debugging source information
// to point to the installed version of the source file. Otherwise, fail silently.
if (verbose) whisper("Updating debug symbols for ", dest, "/lib", lib_dir_name, SHARED_SUFFIX);
- int result = system(String(as_owner, "debugedit -b ", lib_dir,
- " -d '", dest, "'"
- " '", dest, "/lib", lib_dir_name, version_suffix, SHARED_SUFFIX, "' "
+ int result = system(String(as_owner, "debugedit -b ", lib_dir, " -d '", dest,
+ "'"
+ " '",
+ dest, "/lib", lib_dir_name, version_suffix, SHARED_SUFFIX,
+ "' "
">/dev/null 2>/dev/null"));
(void)result;
- print("Installed \033[1m", lib_dir_name, "\033[m to "TOMO_PREFIX"/share/tomo_"TOMO_VERSION"/installed/", lib_dir_name, version_suffix);
+ print("Installed \033[1m", lib_dir_name, "\033[m to " TOMO_PREFIX "/share/tomo_" TOMO_VERSION "/installed/",
+ lib_dir_name, version_suffix);
}
-void compile_files(env_t *env, List_t to_compile, List_t *object_files, List_t *extra_ldlibs)
-{
+void compile_files(env_t *env, List_t to_compile, List_t *object_files, List_t *extra_ldlibs) {
Table_t to_link = {};
Table_t dependency_files = {};
for (int64_t i = 0; i < to_compile.length; i++) {
- Path_t filename = *(Path_t*)(to_compile.data + i*to_compile.stride);
+ Path_t filename = *(Path_t *)(to_compile.data + i * to_compile.stride);
Text_t extension = Path$extension(filename, true);
if (!Text$equal_values(extension, Text("tm")))
print_err("Not a valid .tm file: \x1b[31;1m", filename, "\x1b[m");
- if (!Path$is_file(filename, true))
- print_err("Couldn't find file: ", filename);
+ if (!Path$is_file(filename, true)) print_err("Couldn't find file: ", filename);
build_file_dependency_graph(filename, &dependency_files, &to_link);
}
@@ -488,14 +448,14 @@ void compile_files(env_t *env, List_t to_compile, List_t *object_files, List_t *
struct {
Path_t filename;
staleness_t staleness;
- } *entry = (dependency_files.entries.data + i*dependency_files.entries.stride);
+ } *entry = (dependency_files.entries.data + i * dependency_files.entries.stride);
Path_t id_file = build_file(entry->filename, ".id");
if (!Path$exists(id_file)) {
static const char id_chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
- char id_str[8];
+ char id_str[8];
for (int j = 0; j < (int)sizeof(id_str); j++) {
- id_str[j] = id_chars[random_range(0, sizeof(id_chars)-1)];
+ id_str[j] = id_chars[random_range(0, sizeof(id_chars) - 1)];
}
Text_t filename_id = Text("");
Text_t base = Path$base_name(entry->filename);
@@ -516,19 +476,18 @@ void compile_files(env_t *env, List_t to_compile, List_t *object_files, List_t *
struct {
Path_t filename;
staleness_t staleness;
- } *entry = (dependency_files.entries.data + i*dependency_files.entries.stride);
+ } *entry = (dependency_files.entries.data + i * dependency_files.entries.stride);
if (entry->staleness.h || clean_build) {
transpile_header(env, entry->filename);
entry->staleness.o = true;
} else {
if (verbose) whisper("Unchanged: ", build_file(entry->filename, ".h"));
- if (show_codegen.length > 0)
- xsystem(show_codegen, " <", build_file(entry->filename, ".h"));
+ if (show_codegen.length > 0) xsystem(show_codegen, " <", build_file(entry->filename, ".h"));
}
}
- env->imports = new(Table_t);
+ env->imports = new (Table_t);
struct child_s {
struct child_s *next;
@@ -541,26 +500,23 @@ void compile_files(env_t *env, List_t to_compile, List_t *object_files, List_t *
struct {
Path_t filename;
staleness_t staleness;
- } *entry = (dependency_files.entries.data + i*dependency_files.entries.stride);
+ } *entry = (dependency_files.entries.data + i * dependency_files.entries.stride);
if (!clean_build && !entry->staleness.c && !entry->staleness.h && !entry->staleness.o
&& !is_config_outdated(entry->filename)) {
if (verbose) whisper("Unchanged: ", build_file(entry->filename, ".c"));
- if (show_codegen.length > 0)
- xsystem(show_codegen, " <", build_file(entry->filename, ".c"));
+ if (show_codegen.length > 0) xsystem(show_codegen, " <", build_file(entry->filename, ".c"));
if (verbose) whisper("Unchanged: ", build_file(entry->filename, ".o"));
continue;
}
pid_t pid = fork();
if (pid == 0) {
- if (clean_build || entry->staleness.c)
- transpile_code(env, entry->filename);
+ if (clean_build || entry->staleness.c) transpile_code(env, entry->filename);
else if (verbose) whisper("Unchanged: ", build_file(entry->filename, ".c"));
- if (!stop_at_transpile)
- compile_object_file(entry->filename);
+ if (!stop_at_transpile) compile_object_file(entry->filename);
_exit(EXIT_SUCCESS);
}
- child_processes = new(struct child_s, .next=child_processes, .pid=pid);
+ child_processes = new (struct child_s, .next = child_processes, .pid = pid);
}
for (; child_processes; child_processes = child_processes->next)
@@ -571,7 +527,7 @@ void compile_files(env_t *env, List_t to_compile, List_t *object_files, List_t *
struct {
Path_t filename;
staleness_t staleness;
- } *entry = (dependency_files.entries.data + i*dependency_files.entries.stride);
+ } *entry = (dependency_files.entries.data + i * dependency_files.entries.stride);
Path_t path = entry->filename;
path = build_file(path, ".o");
List$insert(object_files, &path, I(0), sizeof(Path_t));
@@ -579,44 +535,39 @@ void compile_files(env_t *env, List_t to_compile, List_t *object_files, List_t *
}
if (extra_ldlibs) {
for (int64_t i = 0; i < to_link.entries.length; i++) {
- Text_t lib = *(Text_t*)(to_link.entries.data + i*to_link.entries.stride);
+ Text_t lib = *(Text_t *)(to_link.entries.data + i * to_link.entries.stride);
List$insert(extra_ldlibs, &lib, I(0), sizeof(Text_t));
}
}
}
-bool is_config_outdated(Path_t path)
-{
+bool is_config_outdated(Path_t path) {
OptionalText_t config = Path$read(build_file(path, ".config"));
if (config.length < 0) return true;
return !Text$equal_values(config, config_summary);
}
-void build_file_dependency_graph(Path_t path, Table_t *to_compile, Table_t *to_link)
-{
- if (Table$has_value(*to_compile, path, Table$info(&Path$info, &Byte$info)))
- return;
+void build_file_dependency_graph(Path_t path, Table_t *to_compile, Table_t *to_link) {
+ if (Table$has_value(*to_compile, path, Table$info(&Path$info, &Byte$info))) return;
staleness_t staleness = {
- .h=is_stale(build_file(path, ".h"), Path$sibling(path, Text("modules.ini")), true)
- || is_stale(build_file(path, ".h"), build_file(path, ":modules.ini"), true)
- || is_stale(build_file(path, ".h"), path, false)
- || is_stale(build_file(path, ".h"), build_file(path, ".id"), false),
- .c=is_stale(build_file(path, ".c"), Path$sibling(path, Text("modules.ini")), true)
- || is_stale(build_file(path, ".c"), build_file(path, ":modules.ini"), true)
- || is_stale(build_file(path, ".c"), path, false)
- || is_stale(build_file(path, ".c"), build_file(path, ".id"), false),
+ .h = is_stale(build_file(path, ".h"), Path$sibling(path, Text("modules.ini")), true)
+ || is_stale(build_file(path, ".h"), build_file(path, ":modules.ini"), true)
+ || is_stale(build_file(path, ".h"), path, false)
+ || is_stale(build_file(path, ".h"), build_file(path, ".id"), false),
+ .c = is_stale(build_file(path, ".c"), Path$sibling(path, Text("modules.ini")), true)
+ || is_stale(build_file(path, ".c"), build_file(path, ":modules.ini"), true)
+ || is_stale(build_file(path, ".c"), path, false)
+ || is_stale(build_file(path, ".c"), build_file(path, ".id"), false),
};
- staleness.o = staleness.c || staleness.h
- || is_stale(build_file(path, ".o"), build_file(path, ".c"), false)
- || is_stale(build_file(path, ".o"), build_file(path, ".h"), false);
+ staleness.o = staleness.c || staleness.h || is_stale(build_file(path, ".o"), build_file(path, ".c"), false)
+ || is_stale(build_file(path, ".o"), build_file(path, ".h"), false);
Table$set(to_compile, &path, &staleness, Table$info(&Path$info, &Byte$info));
assert(Text$equal_values(Path$extension(path, true), Text("tm")));
ast_t *ast = parse_file(Path$as_c_string(path), NULL);
- if (!ast)
- print_err("Could not parse file: ", path);
+ if (!ast) print_err("Could not parse file: ", path);
for (ast_list_t *stmt = Match(ast, Block)->statements; stmt; stmt = stmt->next) {
ast_t *stmt_ast = stmt->ast;
@@ -626,14 +577,10 @@ void build_file_dependency_graph(Path_t path, Table_t *to_compile, Table_t *to_l
switch (use->what) {
case USE_LOCAL: {
Path_t dep_tm = Path$resolved(Path$from_str(use->path), Path$parent(path));
- if (!Path$is_file(dep_tm, true))
- code_err(stmt_ast, "Not a valid file: ", dep_tm);
- if (is_stale(build_file(path, ".h"), dep_tm, false))
- staleness.h = true;
- if (is_stale(build_file(path, ".c"), dep_tm, false))
- staleness.c = true;
- if (staleness.c || staleness.h)
- staleness.o = true;
+ if (!Path$is_file(dep_tm, true)) code_err(stmt_ast, "Not a valid file: ", dep_tm);
+ if (is_stale(build_file(path, ".h"), dep_tm, false)) staleness.h = true;
+ if (is_stale(build_file(path, ".c"), dep_tm, false)) staleness.c = true;
+ if (staleness.c || staleness.h) staleness.o = true;
Table$set(to_compile, &path, &staleness, Table$info(&Path$info, &Byte$info));
build_file_dependency_graph(dep_tm, to_compile, to_link);
break;
@@ -641,16 +588,17 @@ void build_file_dependency_graph(Path_t path, Table_t *to_compile, Table_t *to_l
case USE_MODULE: {
module_info_t mod = get_module_info(stmt_ast);
const char *full_name = mod.version ? String(mod.name, "_", mod.version) : mod.name;
- Text_t lib = Texts(Text("-Wl,-rpath,'"),
- Text(TOMO_PREFIX "/share/tomo_"TOMO_VERSION"/installed/"), Text$from_str(full_name),
- Text("' '" TOMO_PREFIX "/share/tomo_"TOMO_VERSION"/installed/"),
- Text$from_str(full_name), Text("/lib"), Text$from_str(full_name), Text(SHARED_SUFFIX "'"));
+ Text_t lib =
+ Texts(Text("-Wl,-rpath,'"), Text(TOMO_PREFIX "/share/tomo_" TOMO_VERSION "/installed/"),
+ Text$from_str(full_name), Text("' '" TOMO_PREFIX "/share/tomo_" TOMO_VERSION "/installed/"),
+ Text$from_str(full_name), Text("/lib"), Text$from_str(full_name), Text(SHARED_SUFFIX "'"));
Table$set(to_link, &lib, NULL, Table$info(&Text$info, &Void$info));
- List_t children = Path$glob(Path$from_str(String(TOMO_PREFIX"/share/tomo_"TOMO_VERSION"/installed/", full_name, "/[!._0-9]*.tm")));
+ List_t children = Path$glob(Path$from_str(
+ String(TOMO_PREFIX "/share/tomo_" TOMO_VERSION "/installed/", full_name, "/[!._0-9]*.tm")));
for (int64_t i = 0; i < children.length; i++) {
- Path_t *child = (Path_t*)(children.data + i*children.stride);
- Table_t discarded = {.fallback=to_compile};
+ Path_t *child = (Path_t *)(children.data + i * children.stride);
+ Table_t discarded = {.fallback = to_compile};
build_file_dependency_graph(*child, &discarded, to_link);
}
break;
@@ -671,9 +619,9 @@ void build_file_dependency_graph(Path_t path, Table_t *to_compile, Table_t *to_l
}
break;
}
- case USE_HEADER: case USE_C_CODE: {
- if (use->path[0] == '<')
- break;
+ case USE_HEADER:
+ case USE_C_CODE: {
+ if (use->path[0] == '<') break;
Path_t dep_path = Path$resolved(Path$from_str(use->path), Path$parent(path));
if (is_stale(build_file(path, ".o"), dep_path, false)) {
@@ -687,38 +635,36 @@ void build_file_dependency_graph(Path_t path, Table_t *to_compile, Table_t *to_l
}
}
-time_t latest_included_modification_time(Path_t path)
-{
+time_t latest_included_modification_time(Path_t path) {
static Table_t c_modification_times = {};
- const TypeInfo_t time_info = {.size=sizeof(time_t), .align=__alignof__(time_t), .tag=OpaqueInfo};
+ const TypeInfo_t time_info = {.size = sizeof(time_t), .align = __alignof__(time_t), .tag = OpaqueInfo};
time_t *cached_latest = Table$get(c_modification_times, &path, Table$info(&Path$info, &time_info));
if (cached_latest) return *cached_latest;
struct stat s;
time_t latest = 0;
- if (stat(Path$as_c_string(path), &s) == 0)
- latest = s.st_mtime;
+ if (stat(Path$as_c_string(path), &s) == 0) latest = s.st_mtime;
Table$set(&c_modification_times, &path, &latest, Table$info(&Path$info, &time_info));
OptionalClosure_t by_line = Path$by_line(path);
if (by_line.fn == NULL) return 0;
- OptionalText_t (*next_line)(void*) = by_line.fn;
+ OptionalText_t (*next_line)(void *) = by_line.fn;
Path_t parent = Path$parent(path);
bool allow_dot_include = Path$has_extension(path, Text("s")) || Path$has_extension(path, Text("S"));
- for (Text_t line; (line=next_line(by_line.userdata)).length >= 0; ) {
+ for (Text_t line; (line = next_line(by_line.userdata)).length >= 0;) {
line = Text$trim(line, Text(" \t"), true, false);
- if (!Text$starts_with(line, Text("#include"), NULL) && !(allow_dot_include && Text$starts_with(line, Text(".include"), NULL)))
+ if (!Text$starts_with(line, Text("#include"), NULL)
+ && !(allow_dot_include && Text$starts_with(line, Text(".include"), NULL)))
continue;
// Check for `"` after `#include` or `.include` and some spaces:
- if (!Text$starts_with(Text$trim(Text$from(line, I(9)), Text(" \t"), true, false), Text("\""), NULL))
- continue;
+ if (!Text$starts_with(Text$trim(Text$from(line, I(9)), Text(" \t"), true, false), Text("\""), NULL)) continue;
List_t chunks = Text$split(line, Text("\""));
if (chunks.length < 3) // Should be `#include "foo" ...` -> ["#include ", "foo", "..."]
continue;
- Text_t included = *(Text_t*)(chunks.data + 1*chunks.stride);
+ Text_t included = *(Text_t *)(chunks.data + 1 * chunks.stride);
Path_t included_path = Path$resolved(Path$from_text(included), parent);
time_t included_time = latest_included_modification_time(included_path);
if (included_time > latest) {
@@ -729,8 +675,7 @@ time_t latest_included_modification_time(Path_t path)
return latest;
}
-bool is_stale(Path_t path, Path_t relative_to, bool ignore_missing)
-{
+bool is_stale(Path_t path, Path_t relative_to, bool ignore_missing) {
struct stat target_stat;
if (stat(Path$as_c_string(path), &target_stat) != 0) {
if (ignore_missing) return false;
@@ -739,8 +684,7 @@ bool is_stale(Path_t path, Path_t relative_to, bool ignore_missing)
#ifdef __linux__
// Any file older than the compiler is stale:
- if (target_stat.st_mtime < compiler_stat.st_mtime)
- return true;
+ if (target_stat.st_mtime < compiler_stat.st_mtime) return true;
#endif
if (Path$has_extension(relative_to, Text("c")) || Path$has_extension(relative_to, Text("h"))
@@ -757,55 +701,44 @@ bool is_stale(Path_t path, Path_t relative_to, bool ignore_missing)
return target_stat.st_mtime < relative_to_stat.st_mtime;
}
-bool is_stale_for_any(Path_t path, List_t relative_to, bool ignore_missing)
-{
+bool is_stale_for_any(Path_t path, List_t relative_to, bool ignore_missing) {
for (int64_t i = 0; i < relative_to.length; i++) {
- Path_t r = *(Path_t*)(relative_to.data + i*relative_to.stride);
- if (is_stale(path, r, ignore_missing))
- return true;
+ Path_t r = *(Path_t *)(relative_to.data + i * relative_to.stride);
+ if (is_stale(path, r, ignore_missing)) return true;
}
return false;
}
-void transpile_header(env_t *base_env, Path_t path)
-{
+void transpile_header(env_t *base_env, Path_t path) {
Path_t h_filename = build_file(path, ".h");
ast_t *ast = parse_file(Path$as_c_string(path), NULL);
- if (!ast)
- print_err("Could not parse file: ", path);
+ if (!ast) print_err("Could not parse file: ", path);
env_t *module_env = load_module_env(base_env, ast);
Text_t h_code = compile_file_header(module_env, Path$resolved(h_filename, Path$from_str(".")), ast);
FILE *header = fopen(Path$as_c_string(h_filename), "w");
- if (!header)
- print_err("Failed to open header file: ", h_filename);
+ if (!header) print_err("Failed to open header file: ", h_filename);
Text$print(header, h_code);
- if (fclose(header) == -1)
- print_err("Failed to write header file: ", h_filename);
+ if (fclose(header) == -1) print_err("Failed to write header file: ", h_filename);
- if (!quiet)
- print("Transpiled header:\t", h_filename);
+ if (!quiet) print("Transpiled header:\t", h_filename);
- if (show_codegen.length > 0)
- xsystem(show_codegen, " <", h_filename);
+ if (show_codegen.length > 0) xsystem(show_codegen, " <", h_filename);
}
-void transpile_code(env_t *base_env, Path_t path)
-{
+void transpile_code(env_t *base_env, Path_t path) {
Path_t c_filename = build_file(path, ".c");
ast_t *ast = parse_file(Path$as_c_string(path), NULL);
- if (!ast)
- print_err("Could not parse file: ", path);
+ if (!ast) print_err("Could not parse file: ", path);
env_t *module_env = load_module_env(base_env, ast);
Text_t c_code = compile_file(module_env, ast);
FILE *c_file = fopen(Path$as_c_string(c_filename), "w");
- if (!c_file)
- print_err("Failed to write C file: ", c_filename);
+ if (!c_file) print_err("Failed to write C file: ", c_filename);
Text$print(c_file, c_code);
@@ -814,54 +747,43 @@ void transpile_code(env_t *base_env, Path_t path)
if (main_binding && main_binding->type->tag == FunctionType) {
type_t *ret = Match(main_binding->type, FunctionType)->ret;
if (ret->tag != VoidType && ret->tag != AbortType)
- compiler_err(ast->file, ast->start, ast->end,
- "The main() function in this file has a return type of ", type_to_str(ret),
- ", but it should not have any return value!");
+ compiler_err(ast->file, ast->start, ast->end, "The main() function in this file has a return type of ",
+ type_to_str(ret), ", but it should not have any return value!");
- Text$print(c_file, Texts(
- "int parse_and_run$$", main_binding->code, "(int argc, char *argv[]) {\n",
- module_env->do_source_mapping ? Text("#line 1\n") : EMPTY_TEXT,
- "tomo_init();\n",
- namespace_name(module_env, module_env->namespace, Text("$initialize")), "();\n"
- "\n",
- compile_cli_arg_call(module_env, main_binding->code, main_binding->type, version),
- "return 0;\n"
- "}\n"));
+ Text$print(c_file, Texts("int parse_and_run$$", main_binding->code, "(int argc, char *argv[]) {\n",
+ module_env->do_source_mapping ? Text("#line 1\n") : EMPTY_TEXT, "tomo_init();\n",
+ namespace_name(module_env, module_env->namespace, Text("$initialize")),
+ "();\n"
+ "\n",
+ compile_cli_arg_call(module_env, main_binding->code, main_binding->type, version),
+ "return 0;\n"
+ "}\n"));
}
- if (fclose(c_file) == -1)
- print_err("Failed to output C code to ", c_filename);
+ if (fclose(c_file) == -1) print_err("Failed to output C code to ", c_filename);
- if (!quiet)
- print("Transpiled code:\t", c_filename);
+ if (!quiet) print("Transpiled code:\t", c_filename);
- if (show_codegen.length > 0)
- xsystem(show_codegen, " <", c_filename);
+ if (show_codegen.length > 0) xsystem(show_codegen, " <", c_filename);
}
-void compile_object_file(Path_t path)
-{
+void compile_object_file(Path_t path) {
Path_t obj_file = build_file(path, ".o");
Path_t c_file = build_file(path, ".c");
FILE *prog = run_cmd(cc, " ", cflags, " -O", optimization, " -c ", c_file, " -o ", obj_file);
- if (!prog)
- print_err("Failed to run C compiler: ", cc);
+ if (!prog) print_err("Failed to run C compiler: ", cc);
int status = pclose(prog);
- if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
- exit(EXIT_FAILURE);
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) exit(EXIT_FAILURE);
Path$write(build_file(path, ".config"), config_summary, 0644);
- if (!quiet)
- print("Compiled object:\t", obj_file);
+ if (!quiet) print("Compiled object:\t", obj_file);
}
-Path_t compile_executable(env_t *base_env, Path_t path, Path_t exe_path, List_t object_files, List_t extra_ldlibs)
-{
+Path_t compile_executable(env_t *base_env, Path_t path, Path_t exe_path, List_t object_files, List_t extra_ldlibs) {
ast_t *ast = parse_file(Path$as_c_string(path), NULL);
- if (!ast)
- print_err("Could not parse file ", path);
+ if (!ast) print_err("Could not parse file ", path);
env_t *env = load_module_env(base_env, ast);
binding_t *main_binding = get_binding(env, "main");
if (!main_binding || main_binding->type->tag != FunctionType)
@@ -875,15 +797,16 @@ Path_t compile_executable(env_t *base_env, Path_t path, Path_t exe_path, List_t
return exe_path;
}
- FILE *runner = run_cmd(cc, " ", cflags, " -O", optimization, " ", ldflags, " ", ldlibs, " ", list_text(extra_ldlibs), " ",
- paths_str(object_files), " -x c - -o ", exe_path);
- Text_t program = Texts(
- "extern int parse_and_run$$", main_binding->code, "(int argc, char *argv[]);\n"
- "__attribute__ ((noinline))\n"
- "int main(int argc, char *argv[]) {\n"
- "\treturn parse_and_run$$", main_binding->code, "(argc, argv);\n"
- "}\n"
- );
+ FILE *runner = run_cmd(cc, " ", cflags, " -O", optimization, " ", ldflags, " ", ldlibs, " ",
+ list_text(extra_ldlibs), " ", paths_str(object_files), " -x c - -o ", exe_path);
+ Text_t program = Texts("extern int parse_and_run$$", main_binding->code,
+ "(int argc, char *argv[]);\n"
+ "__attribute__ ((noinline))\n"
+ "int main(int argc, char *argv[]) {\n"
+ "\treturn parse_and_run$$",
+ main_binding->code,
+ "(argc, argv);\n"
+ "}\n");
if (show_codegen.length > 0) {
FILE *out = run_cmd(show_codegen);
@@ -893,11 +816,9 @@ Path_t compile_executable(env_t *base_env, Path_t path, Path_t exe_path, List_t
Text$print(runner, program);
int status = pclose(runner);
- if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
- exit(EXIT_FAILURE);
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) exit(EXIT_FAILURE);
- if (!quiet)
- print("Compiled executable:\t", exe_path);
+ if (!quiet) print("Compiled executable:\t", exe_path);
return exe_path;
}
diff --git a/src/typecheck.c b/src/typecheck.c
index 19d6c09f..680d3049 100644
--- a/src/typecheck.c
+++ b/src/typecheck.c
@@ -20,8 +20,7 @@
#include "typecheck.h"
#include "types.h"
-type_t *parse_type_ast(env_t *env, type_ast_t *ast)
-{
+type_t *parse_type_ast(env_t *env, type_ast_t *ast) {
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wswitch-default"
@@ -51,7 +50,7 @@ type_t *parse_type_ast(env_t *env, type_ast_t *ast)
type_t *pointed_t = parse_type_ast(env, ptr->pointed);
if (pointed_t->tag == VoidType)
code_err(ast, "Void pointers are not supported. You probably meant 'Memory' instead of 'Void'");
- return Type(PointerType, .pointed=pointed_t, .is_stack=ptr->is_stack);
+ return Type(PointerType, .pointed = pointed_t, .is_stack = ptr->is_stack);
}
case ListTypeAST: {
type_ast_t *item_type = Match(ast, ListTypeAST)->item;
@@ -61,8 +60,9 @@ type_t *parse_type_ast(env_t *env, type_ast_t *ast)
code_err(item_type, "Lists can't have stack references because the list may outlive the stack frame.");
if (type_size(item_t) > LIST_MAX_STRIDE)
code_err(ast, "This list holds items that take up ", (uint64_t)type_size(item_t),
- " bytes, but the maximum supported size is ", (int64_t)LIST_MAX_STRIDE, " bytes. Consider using a list of pointers instead.");
- return Type(ListType, .item_type=item_t);
+ " bytes, but the maximum supported size is ", (int64_t)LIST_MAX_STRIDE,
+ " bytes. Consider using a list of pointers instead.");
+ return Type(ListType, .item_type = item_t);
}
case SetTypeAST: {
type_ast_t *item_type = Match(ast, SetTypeAST)->item;
@@ -72,8 +72,9 @@ type_t *parse_type_ast(env_t *env, type_ast_t *ast)
code_err(item_type, "Sets can't have stack references because the list may outlive the stack frame.");
if (type_size(item_t) > LIST_MAX_STRIDE)
code_err(ast, "This set holds items that take up ", (uint64_t)type_size(item_t),
- " bytes, but the maximum supported size is ", (int64_t)LIST_MAX_STRIDE, " bytes. Consider using an set of pointers instead.");
- return Type(SetType, .item_type=item_t);
+ " bytes, but the maximum supported size is ", (int64_t)LIST_MAX_STRIDE,
+ " bytes. Consider using an set of pointers instead.");
+ return Type(SetType, .item_type = item_t);
}
case TableTypeAST: {
DeclareMatch(table_type, ast, TableTypeAST);
@@ -86,39 +87,38 @@ type_t *parse_type_ast(env_t *env, type_ast_t *ast)
type_t *val_type = parse_type_ast(env, table_type->value);
if (!val_type) code_err(table_type->value, "I can't figure out what type this is.");
if (has_stack_memory(val_type))
- code_err(table_type->value, "Tables can't have stack references because the list may outlive the stack frame.");
+ code_err(table_type->value,
+ "Tables can't have stack references because the list may outlive the stack frame.");
else if (val_type->tag == OptionalType)
code_err(ast, "Tables with optional-typed values are not currently supported");
- return Type(TableType, .key_type=key_type, .value_type=val_type, .env=env, .default_value=table_type->default_value);
+ return Type(TableType, .key_type = key_type, .value_type = val_type, .env = env,
+ .default_value = table_type->default_value);
}
case FunctionTypeAST: {
DeclareMatch(fn, ast, FunctionTypeAST);
type_t *ret_t = fn->ret ? parse_type_ast(env, fn->ret) : Type(VoidType);
if (has_stack_memory(ret_t))
- code_err(fn->ret, "Functions are not allowed to return stack references, because the reference may no longer exist on the stack.");
+ code_err(fn->ret, "Functions are not allowed to return stack references, because the reference may no "
+ "longer exist on the stack.");
arg_t *type_args = NULL;
for (arg_ast_t *arg = fn->args; arg; arg = arg->next) {
- type_args = new(arg_t, .name=arg->name, .next=type_args);
- if (arg->type)
- type_args->type = parse_type_ast(env, arg->type);
- else if (arg->value)
- type_args->type = get_type(env, arg->value);
+ type_args = new (arg_t, .name = arg->name, .next = type_args);
+ if (arg->type) type_args->type = parse_type_ast(env, arg->type);
+ else if (arg->value) type_args->type = get_type(env, arg->value);
- if (arg->value)
- type_args->default_val = arg->value;
+ if (arg->value) type_args->default_val = arg->value;
}
REVERSE_LIST(type_args);
- return Type(ClosureType, Type(FunctionType, .args=type_args, .ret=ret_t));
+ return Type(ClosureType, Type(FunctionType, .args = type_args, .ret = ret_t));
}
case OptionalTypeAST: {
DeclareMatch(opt, ast, OptionalTypeAST);
type_t *t = parse_type_ast(env, opt->type);
if (t->tag == VoidType || t->tag == AbortType || t->tag == ReturnType)
code_err(ast, "Optional ", type_to_str(t), " types are not supported.");
- else if (t->tag == OptionalType)
- code_err(ast, "Nested optional types are not currently supported");
- return Type(OptionalType, .type=t);
+ else if (t->tag == OptionalType) code_err(ast, "Nested optional types are not currently supported");
+ return Type(OptionalType, .type = t);
}
case UnknownTypeAST: code_err(ast, "I don't know how to get this type");
}
@@ -151,19 +151,20 @@ type_t *parse_type_ast(env_t *env, type_ast_t *ast)
// }
// }
-PUREFUNC type_t *get_math_type(env_t *env, ast_t *ast, type_t *lhs_t, type_t *rhs_t)
-{
+PUREFUNC type_t *get_math_type(env_t *env, ast_t *ast, type_t *lhs_t, type_t *rhs_t) {
(void)env;
switch (compare_precision(lhs_t, rhs_t)) {
- case NUM_PRECISION_EQUAL: case NUM_PRECISION_MORE: return lhs_t;
+ case NUM_PRECISION_EQUAL:
+ case NUM_PRECISION_MORE: return lhs_t;
case NUM_PRECISION_LESS: return rhs_t;
- default: code_err(ast, "Math operations between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t), " are not supported");
+ default:
+ code_err(ast, "Math operations between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t),
+ " are not supported");
}
return NULL;
}
-static env_t *load_module(env_t *env, ast_t *module_ast)
-{
+static env_t *load_module(env_t *env, ast_t *module_ast) {
DeclareMatch(use, module_ast, Use);
switch (use->what) {
case USE_LOCAL: {
@@ -171,12 +172,10 @@ static env_t *load_module(env_t *env, ast_t *module_ast)
Path_t source_dir = Path$parent(source_path);
Path_t used_path = Path$resolved(Path$from_str(use->path), source_dir);
- if (!Path$exists(used_path))
- code_err(module_ast, "No such file exists: ", quoted(use->path));
+ if (!Path$exists(used_path)) code_err(module_ast, "No such file exists: ", quoted(use->path));
env_t *module_env = Table$str_get(*env->imports, String(used_path));
- if (module_env)
- return module_env;
+ if (module_env) return module_env;
ast_t *ast = parse_file(String(used_path), NULL);
if (!ast) print_err("Could not compile file ", used_path);
@@ -186,9 +185,10 @@ static env_t *load_module(env_t *env, ast_t *module_ast)
module_info_t mod = get_module_info(module_ast);
glob_t tm_files;
const char *folder = mod.version ? String(mod.name, "_", mod.version) : mod.name;
- if (glob(String(TOMO_PREFIX"/share/tomo_"TOMO_VERSION"/installed/", folder, "/[!._0-9]*.tm"), GLOB_TILDE, NULL, &tm_files) != 0) {
- if (!try_install_module(mod))
- code_err(module_ast, "Could not find or install library");
+ if (glob(String(TOMO_PREFIX "/share/tomo_" TOMO_VERSION "/installed/", folder, "/[!._0-9]*.tm"), GLOB_TILDE,
+ NULL, &tm_files)
+ != 0) {
+ if (!try_install_module(mod)) code_err(module_ast, "Could not find or install library");
}
env_t *module_env = fresh_scope(env);
@@ -203,8 +203,9 @@ static env_t *load_module(env_t *env, ast_t *module_ast)
env_t *subenv = load_module_env(module_file_env, ast);
for (int64_t j = 0; j < subenv->locals->entries.length; j++) {
struct {
- const char *name; binding_t *binding;
- } *entry = subenv->locals->entries.data + j*subenv->locals->entries.stride;
+ const char *name;
+ binding_t *binding;
+ } *entry = subenv->locals->entries.data + j * subenv->locals->entries.stride;
Table$str_set(module_env->locals, entry->name, entry->binding);
}
}
@@ -215,8 +216,7 @@ static env_t *load_module(env_t *env, ast_t *module_ast)
}
}
-void prebind_statement(env_t *env, ast_t *statement)
-{
+void prebind_statement(env_t *env, ast_t *statement) {
switch (statement->tag) {
case DocTest: {
prebind_statement(env, Match(statement, DocTest)->expr);
@@ -229,63 +229,73 @@ void prebind_statement(env_t *env, ast_t *statement)
case StructDef: {
DeclareMatch(def, statement, StructDef);
if (get_binding(env, def->name))
- code_err(statement, "A ", type_to_str(get_binding(env, def->name)->type), " called ", quoted(def->name), " has already been defined");
+ code_err(statement, "A ", type_to_str(get_binding(env, def->name)->type), " called ", quoted(def->name),
+ " has already been defined");
env_t *ns_env = namespace_env(env, def->name);
- type_t *type = Type(StructType, .name=def->name, .opaque=true, .external=def->external, .env=ns_env); // placeholder
+ type_t *type = Type(StructType, .name = def->name, .opaque = true, .external = def->external,
+ .env = ns_env); // placeholder
Table$str_set(env->types, def->name, type);
- set_binding(env, def->name, Type(TypeInfoType, .name=def->name, .type=type, .env=ns_env),
+ set_binding(env, def->name, Type(TypeInfoType, .name = def->name, .type = type, .env = ns_env),
namespace_name(env, env->namespace, Texts(def->name, "$$info")));
- for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt; stmt = stmt->next)
+ for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt;
+ stmt = stmt->next)
prebind_statement(ns_env, stmt->ast);
break;
}
case EnumDef: {
DeclareMatch(def, statement, EnumDef);
if (get_binding(env, def->name))
- code_err(statement, "A ", type_to_str(get_binding(env, def->name)->type), " called ", quoted(def->name), " has already been defined");
+ code_err(statement, "A ", type_to_str(get_binding(env, def->name)->type), " called ", quoted(def->name),
+ " has already been defined");
env_t *ns_env = namespace_env(env, def->name);
- type_t *type = Type(EnumType, .name=def->name, .opaque=true, .env=ns_env); // placeholder
+ type_t *type = Type(EnumType, .name = def->name, .opaque = true, .env = ns_env); // placeholder
Table$str_set(env->types, def->name, type);
- set_binding(env, def->name, Type(TypeInfoType, .name=def->name, .type=type, .env=ns_env),
+ set_binding(env, def->name, Type(TypeInfoType, .name = def->name, .type = type, .env = ns_env),
namespace_name(env, env->namespace, Texts(def->name, "$$info")));
- for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt; stmt = stmt->next)
+ for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt;
+ stmt = stmt->next)
prebind_statement(ns_env, stmt->ast);
break;
}
case LangDef: {
DeclareMatch(def, statement, LangDef);
if (get_binding(env, def->name))
- code_err(statement, "A ", type_to_str(get_binding(env, def->name)->type), " called ", quoted(def->name), " has already been defined");
+ code_err(statement, "A ", type_to_str(get_binding(env, def->name)->type), " called ", quoted(def->name),
+ " has already been defined");
env_t *ns_env = namespace_env(env, def->name);
- type_t *type = Type(TextType, .lang=def->name, .env=ns_env);
+ type_t *type = Type(TextType, .lang = def->name, .env = ns_env);
Table$str_set(env->types, def->name, type);
- set_binding(env, def->name, Type(TypeInfoType, .name=def->name, .type=type, .env=ns_env),
+ set_binding(env, def->name, Type(TypeInfoType, .name = def->name, .type = type, .env = ns_env),
namespace_name(env, env->namespace, Texts(def->name, "$$info")));
- for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt; stmt = stmt->next)
+ for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt;
+ stmt = stmt->next)
prebind_statement(ns_env, stmt->ast);
break;
}
case Extend: {
DeclareMatch(extend, statement, Extend);
env_t *ns_env = namespace_env(env, extend->name);
- env_t *extended = new(env_t);
+ env_t *extended = new (env_t);
*extended = *ns_env;
- extended->locals = new(Table_t, .fallback=env->locals);
- extended->namespace_bindings = new(Table_t, .fallback=env->namespace_bindings);
+ extended->locals = new (Table_t, .fallback = env->locals);
+ extended->namespace_bindings = new (Table_t, .fallback = env->namespace_bindings);
extended->id_suffix = env->id_suffix;
for (ast_list_t *stmt = extend->body ? Match(extend->body, Block)->statements : NULL; stmt; stmt = stmt->next)
prebind_statement(extended, stmt->ast);
List_t new_bindings = extended->locals->entries;
for (int64_t i = 0; i < new_bindings.length; i++) {
- struct { const char *name; binding_t *binding; } *entry = new_bindings.data + i*new_bindings.stride;
+ struct {
+ const char *name;
+ binding_t *binding;
+ } *entry = new_bindings.data + i * new_bindings.stride;
binding_t *clobbered = Table$str_get(*ns_env->locals, entry->name);
if (clobbered && !type_eq(clobbered->type, entry->binding->type))
code_err(statement, "This `extend` block overwrites the binding for ", quoted(entry->name),
- " in the original namespace (with type ", type_to_str(clobbered->type), ") with a new binding with type ",
- type_to_str(entry->binding->type));
+ " in the original namespace (with type ", type_to_str(clobbered->type),
+ ") with a new binding with type ", type_to_str(entry->binding->type));
Table$str_set(ns_env->locals, entry->name, entry->binding);
}
break;
@@ -294,8 +304,7 @@ void prebind_statement(env_t *env, ast_t *statement)
}
}
-void bind_statement(env_t *env, ast_t *statement)
-{
+void bind_statement(env_t *env, ast_t *statement) {
switch (statement->tag) {
case DocTest: {
bind_statement(env, Match(statement, DocTest)->expr);
@@ -311,19 +320,16 @@ void bind_statement(env_t *env, ast_t *statement)
if (streq(name, "_")) // Explicit discard
return;
if (get_binding(env, name))
- code_err(decl->var, "A ", type_to_str(get_binding(env, name)->type), " called ", quoted(name), " has already been defined");
- if (decl->value)
- bind_statement(env, decl->value);
+ code_err(decl->var, "A ", type_to_str(get_binding(env, name)->type), " called ", quoted(name),
+ " has already been defined");
+ if (decl->value) bind_statement(env, decl->value);
type_t *type = decl->type ? parse_type_ast(env, decl->type) : get_type(env, decl->value);
- if (!type)
- code_err(statement, "I couldn't figure out the type of this value");
- if (type->tag == FunctionType)
- type = Type(ClosureType, type);
+ if (!type) code_err(statement, "I couldn't figure out the type of this value");
+ if (type->tag == FunctionType) type = Type(ClosureType, type);
Text_t code;
if (name[0] != '_' && (env->namespace || decl->top_level))
code = namespace_name(env, env->namespace, Text$from_str(name));
- else
- code = Texts("_$", name);
+ else code = Texts("_$", name);
set_binding(env, name, type, code);
break;
}
@@ -339,11 +345,12 @@ void bind_statement(env_t *env, ast_t *statement)
type_t *ret_t = Match(type, FunctionType)->ret;
const char *name = get_type_name(ret_t);
if (!name)
- code_err(statement, "Conversions are only supported for text, struct, and enum types, not ", type_to_str(ret_t));
+ code_err(statement, "Conversions are only supported for text, struct, and enum types, not ",
+ type_to_str(ret_t));
Text_t code = namespace_name(env, env->namespace,
- Texts(name, "$", String(get_line_number(statement->file, statement->start))));
- binding_t binding = {.type=type, .code=code};
+ Texts(name, "$", String(get_line_number(statement->file, statement->start))));
+ binding_t binding = {.type = type, .code = code};
env_t *type_ns = get_namespace_by_type(env, ret_t);
List$insert(&type_ns->namespace->constructors, &binding, I(0), sizeof(binding));
break;
@@ -371,23 +378,34 @@ void bind_statement(env_t *env, ast_t *statement)
file = field_ast->value->file, start = field_ast->value->start, end = field_ast->value->end;
}
if (non_opt_field_t == type)
- compiler_err(file, start, end, "This is a recursive struct that would be infinitely large. Maybe you meant to use an optional '@", type_to_str(type), "?' pointer instead?");
+ compiler_err(file, start, end,
+ "This is a recursive struct that would be infinitely large. Maybe you meant to "
+ "use an optional '@",
+ type_to_str(type), "?' pointer instead?");
else if (non_opt_field_t->tag == StructType && Match(non_opt_field_t, StructType)->external)
- compiler_err(file, start, end, "This is an opaque externally defined struct.\n"
- "I can't use it as a member without knowing what its fields are.\n"
- "Either specify its fields and remove the `opaque` qualifier, or use something like a @", type_to_str(non_opt_field_t), " pointer.");
+ compiler_err(
+ file, start, end,
+ "This is an opaque externally defined struct.\n"
+ "I can't use it as a member without knowing what its fields are.\n"
+ "Either specify its fields and remove the `opaque` qualifier, or use something like a @",
+ type_to_str(non_opt_field_t), " pointer.");
else
- compiler_err(file, start, end, "I'm still in the process of defining the fields of ", type_to_str(field_t), ", so I don't know how to use it as a member."
- "\nTry using a @", type_to_str(field_t), " pointer for this field.");
+ compiler_err(file, start, end, "I'm still in the process of defining the fields of ",
+ type_to_str(field_t),
+ ", so I don't know how to use it as a member."
+ "\nTry using a @",
+ type_to_str(field_t), " pointer for this field.");
}
- fields = new(arg_t, .name=field_ast->name, .type=field_t, .default_val=field_ast->value, .next=fields);
+ fields = new (arg_t, .name = field_ast->name, .type = field_t, .default_val = field_ast->value,
+ .next = fields);
}
REVERSE_LIST(fields);
type->__data.StructType.fields = fields; // populate placeholder
type->__data.StructType.opaque = false;
}
- for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt; stmt = stmt->next)
+ for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt;
+ stmt = stmt->next)
bind_statement(ns_env, stmt->ast);
break;
}
@@ -416,22 +434,32 @@ void bind_statement(env_t *env, ast_t *statement)
file = field_ast->value->file, start = field_ast->value->start, end = field_ast->value->end;
}
if (non_opt_field_t == type)
- compiler_err(file, start, end, "This is a recursive enum that would be infinitely large. Maybe you meant to use an optional '@", type_to_str(type), "?' pointer instead?");
+ compiler_err(file, start, end,
+ "This is a recursive enum that would be infinitely large. Maybe you meant to use "
+ "an optional '@",
+ type_to_str(type), "?' pointer instead?");
else if (non_opt_field_t->tag == StructType && Match(non_opt_field_t, StructType)->external)
- compiler_err(file, start, end, "This is an opaque externally defined struct.\n"
- "I can't use it as a member without knowing what its fields are.\n"
- "Either specify its fields and remove the `opaque` qualifier, or use something like a @", type_to_str(non_opt_field_t), " pointer.");
+ compiler_err(
+ file, start, end,
+ "This is an opaque externally defined struct.\n"
+ "I can't use it as a member without knowing what its fields are.\n"
+ "Either specify its fields and remove the `opaque` qualifier, or use something like a @",
+ type_to_str(non_opt_field_t), " pointer.");
else
- compiler_err(file, start, end, "I'm still in the process of defining the fields of ", type_to_str(field_t),
+ compiler_err(file, start, end, "I'm still in the process of defining the fields of ",
+ type_to_str(field_t),
", so I don't know how to use it as a member."
- "\nTry using a @", type_to_str(field_t), " pointer for this field.");
+ "\nTry using a @",
+ type_to_str(field_t), " pointer for this field.");
}
- fields = new(arg_t, .name=field_ast->name, .type=field_t, .default_val=field_ast->value, .next=fields);
+ fields = new (arg_t, .name = field_ast->name, .type = field_t, .default_val = field_ast->value,
+ .next = fields);
}
REVERSE_LIST(fields);
env_t *member_ns = namespace_env(env, String(def->name, "$", tag_ast->name));
- type_t *tag_type = Type(StructType, .name=String(def->name, "$", tag_ast->name), .fields=fields, .env=member_ns);
- tags = new(tag_t, .name=tag_ast->name, .tag_value=(next_tag++), .type=tag_type, .next=tags);
+ type_t *tag_type =
+ Type(StructType, .name = String(def->name, "$", tag_ast->name), .fields = fields, .env = member_ns);
+ tags = new (tag_t, .name = tag_ast->name, .tag_value = (next_tag++), .type = tag_type, .next = tags);
}
REVERSE_LIST(tags);
type->__data.EnumType.tags = tags;
@@ -439,14 +467,14 @@ void bind_statement(env_t *env, ast_t *statement)
for (tag_t *tag = tags; tag; tag = tag->next) {
if (Match(tag->type, StructType)->fields) { // Constructor:
- type_t *constructor_t = Type(FunctionType, .args=Match(tag->type, StructType)->fields, .ret=type);
+ type_t *constructor_t = Type(FunctionType, .args = Match(tag->type, StructType)->fields, .ret = type);
Text_t tagged_name = namespace_name(env, env->namespace, Texts(def->name, "$tagged$", tag->name));
set_binding(ns_env, tag->name, constructor_t, tagged_name);
- binding_t binding = {.type=constructor_t, .code=tagged_name};
+ binding_t binding = {.type = constructor_t, .code = tagged_name};
List$insert(&ns_env->namespace->constructors, &binding, I(1), sizeof(binding));
} else if (has_any_tags_with_fields) { // Empty singleton value:
Text_t code = Texts("((", namespace_name(env, env->namespace, Texts(def->name, "$$type")), "){",
- namespace_name(env, env->namespace, Texts(def->name, "$tag$", tag->name)), "})");
+ namespace_name(env, env->namespace, Texts(def->name, "$tag$", tag->name)), "})");
set_binding(ns_env, tag->name, type, code);
} else {
Text_t code = namespace_name(env, env->namespace, Texts(def->name, "$tag$", tag->name));
@@ -454,8 +482,9 @@ void bind_statement(env_t *env, ast_t *statement)
}
Table$str_set(env->types, String(def->name, "$", tag->name), tag->type);
}
-
- for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt; stmt = stmt->next) {
+
+ for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt;
+ stmt = stmt->next) {
bind_statement(ns_env, stmt->ast);
}
break;
@@ -463,35 +492,39 @@ void bind_statement(env_t *env, ast_t *statement)
case LangDef: {
DeclareMatch(def, statement, LangDef);
env_t *ns_env = namespace_env(env, def->name);
- type_t *type = Type(TextType, .lang=def->name, .env=ns_env);
+ type_t *type = Type(TextType, .lang = def->name, .env = ns_env);
ns_env->current_type = type;
Table$str_set(env->types, def->name, type);
- set_binding(ns_env, "from_text", NewFunctionType(type, {.name="text", .type=TEXT_TYPE}),
+ set_binding(ns_env, "from_text", NewFunctionType(type, {.name = "text", .type = TEXT_TYPE}),
Texts("(", namespace_name(env, env->namespace, Texts(def->name, "$$type")), ")"));
- for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt; stmt = stmt->next)
+ for (ast_list_t *stmt = def->namespace ? Match(def->namespace, Block)->statements : NULL; stmt;
+ stmt = stmt->next)
bind_statement(ns_env, stmt->ast);
break;
}
case Extend: {
DeclareMatch(extend, statement, Extend);
env_t *ns_env = namespace_env(env, extend->name);
- env_t *extended = new(env_t);
+ env_t *extended = new (env_t);
*extended = *ns_env;
- extended->locals = new(Table_t, .fallback=env->locals);
- extended->namespace_bindings = new(Table_t, .fallback=env->namespace_bindings);
+ extended->locals = new (Table_t, .fallback = env->locals);
+ extended->namespace_bindings = new (Table_t, .fallback = env->namespace_bindings);
extended->id_suffix = env->id_suffix;
for (ast_list_t *stmt = extend->body ? Match(extend->body, Block)->statements : NULL; stmt; stmt = stmt->next)
bind_statement(extended, stmt->ast);
List_t new_bindings = extended->locals->entries;
for (int64_t i = 0; i < new_bindings.length; i++) {
- struct { const char *name; binding_t *binding; } *entry = new_bindings.data + i*new_bindings.stride;
+ struct {
+ const char *name;
+ binding_t *binding;
+ } *entry = new_bindings.data + i * new_bindings.stride;
binding_t *clobbered = Table$str_get(*ns_env->locals, entry->name);
if (clobbered && !type_eq(clobbered->type, entry->binding->type))
code_err(statement, "This `extend` block overwrites the binding for ", quoted(entry->name),
- " in the original namespace (with type ", type_to_str(clobbered->type), ") with a new binding with type ",
- type_to_str(entry->binding->type));
+ " in the original namespace (with type ", type_to_str(clobbered->type),
+ ") with a new binding with type ", type_to_str(entry->binding->type));
Table$str_set(ns_env->locals, entry->name, entry->binding);
}
break;
@@ -502,22 +535,25 @@ void bind_statement(env_t *env, ast_t *statement)
for (Table_t *bindings = module_env->locals; bindings != module_env->globals; bindings = bindings->fallback) {
List_t entries = bindings->entries;
for (int64_t i = 0; i < entries.length; i++) {
- struct { const char *name; binding_t *binding; } *entry = entries.data + entries.stride*i;
- if (entry->name[0] == '_' || streq(entry->name, "main"))
- continue;
+ struct {
+ const char *name;
+ binding_t *binding;
+ } *entry = entries.data + entries.stride * i;
+ if (entry->name[0] == '_' || streq(entry->name, "main")) continue;
binding_t *b = Table$str_get(*env->locals, entry->name);
- if (!b)
- Table$str_set(env->locals, entry->name, entry->binding);
+ if (!b) Table$str_set(env->locals, entry->name, entry->binding);
else if (b != entry->binding)
- code_err(statement, "This module imports a symbol called '", entry->name, "', which would clobber another variable");
+ code_err(statement, "This module imports a symbol called '", entry->name,
+ "', which would clobber another variable");
}
}
for (int64_t i = 0; i < module_env->types->entries.length; i++) {
- struct { const char *name; type_t *type; } *entry = module_env->types->entries.data + module_env->types->entries.stride*i;
- if (entry->name[0] == '_')
- continue;
- if (Table$str_get(*env->types, entry->name))
- continue;
+ struct {
+ const char *name;
+ type_t *type;
+ } *entry = module_env->types->entries.data + module_env->types->entries.stride * i;
+ if (entry->name[0] == '_') continue;
+ if (Table$str_get(*env->types, entry->name)) continue;
Table$str_set(env->types, entry->name, entry->type);
}
@@ -533,8 +569,7 @@ void bind_statement(env_t *env, ast_t *statement)
case Extern: {
DeclareMatch(ext, statement, Extern);
type_t *t = parse_type_ast(env, ext->type);
- if (t->tag == ClosureType)
- t = Match(t, ClosureType)->fn;
+ if (t->tag == ClosureType) t = Match(t, ClosureType)->fn;
set_binding(env, ext->name, t, Text$from_str(ext->name));
break;
}
@@ -542,15 +577,15 @@ void bind_statement(env_t *env, ast_t *statement)
}
}
-type_t *get_function_def_type(env_t *env, ast_t *ast)
-{
+type_t *get_function_def_type(env_t *env, ast_t *ast) {
arg_ast_t *arg_asts = ast->tag == FunctionDef ? Match(ast, FunctionDef)->args : Match(ast, ConvertDef)->args;
- type_ast_t *ret_type = ast->tag == FunctionDef ? Match(ast, FunctionDef)->ret_type : Match(ast, ConvertDef)->ret_type;
+ type_ast_t *ret_type =
+ ast->tag == FunctionDef ? Match(ast, FunctionDef)->ret_type : Match(ast, ConvertDef)->ret_type;
arg_t *args = NULL;
env_t *scope = fresh_scope(env);
for (arg_ast_t *arg = arg_asts; arg; arg = arg->next) {
type_t *t = arg->type ? parse_type_ast(env, arg->type) : get_type(env, arg->value);
- args = new(arg_t, .name=arg->name, .type=t, .default_val=arg->value, .next=args);
+ args = new (arg_t, .name = arg->name, .type = t, .default_val = arg->value, .next = args);
set_binding(scope, arg->name, t, EMPTY_TEXT);
}
REVERSE_LIST(args);
@@ -558,29 +593,26 @@ type_t *get_function_def_type(env_t *env, ast_t *ast)
type_t *ret = ret_type ? parse_type_ast(scope, ret_type) : Type(VoidType);
if (has_stack_memory(ret))
code_err(ast, "Functions can't return stack references because the reference may outlive its stack frame.");
- return Type(FunctionType, .args=args, .ret=ret);
+ return Type(FunctionType, .args = args, .ret = ret);
}
-type_t *get_method_type(env_t *env, ast_t *self, const char *name)
-{
+type_t *get_method_type(env_t *env, ast_t *self, const char *name) {
binding_t *b = get_namespace_binding(env, self, name);
- if (!b || !b->type)
- code_err(self, "No such method: ", type_to_str(get_type(env, self)), ".", name, "(...)");
+ if (!b || !b->type) code_err(self, "No such method: ", type_to_str(get_type(env, self)), ".", name, "(...)");
return b->type;
}
-env_t *when_clause_scope(env_t *env, type_t *subject_t, when_clause_t *clause)
-{
- if (clause->pattern->tag == Var || subject_t->tag != EnumType)
- return env;
+env_t *when_clause_scope(env_t *env, type_t *subject_t, when_clause_t *clause) {
+ if (clause->pattern->tag == Var || subject_t->tag != EnumType) return env;
if (clause->pattern->tag != FunctionCall || Match(clause->pattern, FunctionCall)->fn->tag != Var)
- code_err(clause->pattern, "I only support variables and constructors for pattern matching ", type_to_str(subject_t), " types in a 'when' block");
+ code_err(clause->pattern, "I only support variables and constructors for pattern matching ",
+ type_to_str(subject_t), " types in a 'when' block");
DeclareMatch(fn, clause->pattern, FunctionCall);
const char *tag_name = Match(fn->fn, Var)->name;
type_t *tag_type = NULL;
- tag_t * const tags = Match(subject_t, EnumType)->tags;
+ tag_t *const tags = Match(subject_t, EnumType)->tags;
for (tag_t *tag = tags; tag; tag = tag->next) {
if (streq(tag->name, tag_name)) {
tag_type = tag->type;
@@ -591,14 +623,12 @@ env_t *when_clause_scope(env_t *env, type_t *subject_t, when_clause_t *clause)
if (!tag_type)
code_err(clause->pattern, "There is no tag ", quoted(tag_name), " for the type ", type_to_str(subject_t));
- if (!fn->args)
- return env;
+ if (!fn->args) return env;
env_t *scope = fresh_scope(env);
DeclareMatch(tag_struct, tag_type, StructType);
if (fn->args && !fn->args->next && tag_struct->fields && tag_struct->fields->next) {
- if (fn->args->value->tag != Var)
- code_err(fn->args->value, "I expected a variable here");
+ if (fn->args->value->tag != Var) code_err(fn->args->value, "I expected a variable here");
set_binding(scope, Match(fn->args->value, Var)->name, tag_type, EMPTY_TEXT);
return scope;
}
@@ -606,9 +636,9 @@ env_t *when_clause_scope(env_t *env, type_t *subject_t, when_clause_t *clause)
arg_t *field = tag_struct->fields;
for (arg_ast_t *var = fn->args; var || field; var = var ? var->next : var) {
if (!var)
- code_err(clause->pattern, "The field ", type_to_str(subject_t), ".", tag_name, ".", field->name, " wasn't accounted for");
- if (!field)
- code_err(var->value, "This is one more field than ", type_to_str(subject_t), " has");
+ code_err(clause->pattern, "The field ", type_to_str(subject_t), ".", tag_name, ".", field->name,
+ " wasn't accounted for");
+ if (!field) code_err(var->value, "This is one more field than ", type_to_str(subject_t), " has");
if (var->value->tag != Var)
code_err(var->value, "I expected this to be a plain variable so I could bind it to a value");
if (!streq(Match(var->value, Var)->name, "_"))
@@ -618,14 +648,12 @@ env_t *when_clause_scope(env_t *env, type_t *subject_t, when_clause_t *clause)
return scope;
}
-type_t *get_clause_type(env_t *env, type_t *subject_t, when_clause_t *clause)
-{
+type_t *get_clause_type(env_t *env, type_t *subject_t, when_clause_t *clause) {
env_t *scope = when_clause_scope(env, subject_t, clause);
return get_type(scope, clause->body);
}
-type_t *get_type(env_t *env, ast_t *ast)
-{
+type_t *get_type(env_t *env, ast_t *ast) {
if (!ast) return NULL;
#ifdef __GNUC__
#pragma GCC diagnostic push
@@ -633,7 +661,7 @@ type_t *get_type(env_t *env, ast_t *ast)
#endif
switch (ast->tag) {
case None: {
- return Type(OptionalType, .type=NULL);
+ return Type(OptionalType, .type = NULL);
}
case Bool: {
return Type(BoolType);
@@ -642,13 +670,14 @@ type_t *get_type(env_t *env, ast_t *ast)
return Type(BigIntType);
}
case Num: {
- return Type(NumType, .bits=TYPE_NBITS64);
+ return Type(NumType, .bits = TYPE_NBITS64);
}
case HeapAllocate: {
type_t *pointed = get_type(env, Match(ast, HeapAllocate)->value);
if (has_stack_memory(pointed))
- code_err(ast, "Stack references cannot be moved to the heap because they may outlive the stack frame they were created in.");
- return Type(PointerType, .pointed=pointed);
+ code_err(ast, "Stack references cannot be moved to the heap because they may outlive the stack frame they "
+ "were created in.");
+ return Type(PointerType, .pointed = pointed);
}
case StackReference: {
// Supported:
@@ -677,24 +706,21 @@ type_t *get_type(env_t *env, ast_t *ast)
code_err(base, "This value might be none, so it can't be safely dereferenced");
} else if (base_type->tag == PointerType) {
DeclareMatch(ptr, base_type, PointerType);
- return Type(PointerType, .pointed=ref_type, .is_stack=ptr->is_stack);
+ return Type(PointerType, .pointed = ref_type, .is_stack = ptr->is_stack);
} else if (base->tag == Var) {
- return Type(PointerType, .pointed=ref_type, .is_stack=true);
+ return Type(PointerType, .pointed = ref_type, .is_stack = true);
}
code_err(ast, "'&' stack references can only be used on the fields of pointers and local variables");
}
- case Index:
- code_err(ast, "'&' stack references are not supported for list or table indexing");
- default:
- return Type(PointerType, .pointed=get_type(env, value), .is_stack=true);
+ case Index: code_err(ast, "'&' stack references are not supported for list or table indexing");
+ default: return Type(PointerType, .pointed = get_type(env, value), .is_stack = true);
}
}
case Optional: {
ast_t *value = Match(ast, Optional)->value;
type_t *t = get_type(env, value);
- if (t->tag == OptionalType)
- code_err(ast, "This value is already optional, it can't be converted to optional");
- return Type(OptionalType, .type=t);
+ if (t->tag == OptionalType) code_err(ast, "This value is already optional, it can't be converted to optional");
+ return Type(OptionalType, .type = t);
}
case NonOptional: {
ast_t *value = Match(ast, NonOptional)->value;
@@ -730,21 +756,20 @@ type_t *get_type(env_t *env, ast_t *ast)
env_t *scope = env;
while (item_ast->tag == Comprehension) {
DeclareMatch(comp, item_ast, Comprehension);
- scope = for_scope(
- scope, FakeAST(For, .iter=comp->iter, .vars=comp->vars));
+ scope = for_scope(scope, FakeAST(For, .iter = comp->iter, .vars = comp->vars));
item_ast = comp->expr;
}
type_t *t2 = get_type(scope, item_ast);
type_t *merged = item_type ? type_or_type(item_type, t2) : t2;
- if (!merged)
- return Type(ListType, .item_type=NULL);
+ if (!merged) return Type(ListType, .item_type = NULL);
item_type = merged;
}
if (item_type && has_stack_memory(item_type))
- code_err(ast, "Lists cannot hold stack references, because the list may outlive the stack frame the reference was created in.");
+ code_err(ast, "Lists cannot hold stack references, because the list may outlive the stack frame the "
+ "reference was created in.");
- return Type(ListType, .item_type=item_type);
+ return Type(ListType, .item_type = item_type);
}
case Set: {
DeclareMatch(set, ast, Set);
@@ -754,22 +779,20 @@ type_t *get_type(env_t *env, ast_t *ast)
env_t *scope = env;
while (item_ast->tag == Comprehension) {
DeclareMatch(comp, item_ast, Comprehension);
- scope = for_scope(
- scope, FakeAST(For, .iter=comp->iter, .vars=comp->vars));
+ scope = for_scope(scope, FakeAST(For, .iter = comp->iter, .vars = comp->vars));
item_ast = comp->expr;
}
type_t *this_item_type = get_type(scope, item_ast);
type_t *item_merged = type_or_type(item_type, this_item_type);
- if (!item_merged)
- return Type(SetType, .item_type=NULL);
+ if (!item_merged) return Type(SetType, .item_type = NULL);
item_type = item_merged;
}
if (item_type && has_stack_memory(item_type))
code_err(ast, "Sets cannot hold stack references because the set may outlive the reference's stack frame.");
- return Type(SetType, .item_type=item_type);
+ return Type(SetType, .item_type = item_type);
}
case Table: {
DeclareMatch(table, ast, Table);
@@ -780,8 +803,7 @@ type_t *get_type(env_t *env, ast_t *ast)
env_t *scope = env;
while (entry_ast->tag == Comprehension) {
DeclareMatch(comp, entry_ast, Comprehension);
- scope = for_scope(
- scope, FakeAST(For, .iter=comp->iter, .vars=comp->vars));
+ scope = for_scope(scope, FakeAST(For, .iter = comp->iter, .vars = comp->vars));
entry_ast = comp->expr;
}
@@ -790,56 +812,52 @@ type_t *get_type(env_t *env, ast_t *ast)
type_t *value_t = get_type(scope, e->value);
type_t *key_merged = key_type ? type_or_type(key_type, key_t) : key_t;
- if (!key_merged)
- ambiguous_key_type = true;
+ if (!key_merged) ambiguous_key_type = true;
key_type = key_merged;
type_t *val_merged = value_type ? type_or_type(value_type, value_t) : value_t;
- if (!val_merged)
- ambiguous_value_type = true;
+ if (!val_merged) ambiguous_value_type = true;
value_type = val_merged;
}
- if (ambiguous_key_type)
- key_type = NULL;
+ if (ambiguous_key_type) key_type = NULL;
- if (ambiguous_value_type)
- value_type = NULL;
+ if (ambiguous_value_type) value_type = NULL;
if ((key_type && has_stack_memory(key_type)) || (value_type && has_stack_memory(value_type)))
- code_err(ast, "Tables cannot hold stack references because the table may outlive the reference's stack frame.");
+ code_err(ast,
+ "Tables cannot hold stack references because the table may outlive the reference's stack frame.");
- return Type(TableType, .key_type=key_type, .value_type=value_type, .default_value=table->default_value, .env=env);
+ return Type(TableType, .key_type = key_type, .value_type = value_type, .default_value = table->default_value,
+ .env = env);
}
case TableEntry: {
code_err(ast, "Table entries should not be typechecked directly");
}
case Comprehension: {
DeclareMatch(comp, ast, Comprehension);
- env_t *scope = for_scope(env, FakeAST(For, .iter=comp->iter, .vars=comp->vars));
+ env_t *scope = for_scope(env, FakeAST(For, .iter = comp->iter, .vars = comp->vars));
if (comp->expr->tag == Comprehension) {
return get_type(scope, comp->expr);
} else if (comp->expr->tag == TableEntry) {
DeclareMatch(e, comp->expr, TableEntry);
- return Type(TableType, .key_type=get_type(scope, e->key), .value_type=get_type(scope, e->value), .env=env);
+ return Type(TableType, .key_type = get_type(scope, e->key), .value_type = get_type(scope, e->value),
+ .env = env);
} else {
- return Type(ListType, .item_type=get_type(scope, comp->expr));
+ return Type(ListType, .item_type = get_type(scope, comp->expr));
}
}
case FieldAccess: {
DeclareMatch(access, ast, FieldAccess);
type_t *fielded_t = get_type(env, access->fielded);
if (access->field[0] == '_') {
- if (!env->current_type || !type_eq(env->current_type,
- fielded_t->tag == TypeInfoType
- ? Match(fielded_t, TypeInfoType)->type
- : value_type(fielded_t)))
+ if (!env->current_type
+ || !type_eq(env->current_type, fielded_t->tag == TypeInfoType ? Match(fielded_t, TypeInfoType)->type
+ : value_type(fielded_t)))
code_err(ast, "Fields beginning with underscores like '", access->field,
"' can't be accessed outside the scope where the type (",
- type_to_text(
- fielded_t->tag == TypeInfoType
- ? Match(fielded_t, TypeInfoType)->type
- : value_type(fielded_t)),
+ type_to_text(fielded_t->tag == TypeInfoType ? Match(fielded_t, TypeInfoType)->type
+ : value_type(fielded_t)),
") is defined.");
}
if (fielded_t->tag == ModuleType) {
@@ -855,8 +873,7 @@ type_t *get_type(env_t *env, ast_t *ast)
return b->type;
}
type_t *field_t = get_field_type(fielded_t, access->field);
- if (!field_t)
- code_err(ast, type_to_str(fielded_t), " objects don't have a field called '", access->field, "'");
+ if (!field_t) code_err(ast, type_to_str(fielded_t), " objects don't have a field called '", access->field, "'");
return field_t;
}
case Index: {
@@ -865,8 +882,7 @@ type_t *get_type(env_t *env, ast_t *ast)
if (indexed_t->tag == OptionalType && !indexing->index)
code_err(ast, "You're attempting to dereference a value whose type indicates it could be none");
- if (indexed_t->tag == PointerType && !indexing->index)
- return Match(indexed_t, PointerType)->pointed;
+ if (indexed_t->tag == PointerType && !indexing->index) return Match(indexed_t, PointerType)->pointed;
type_t *value_t = value_type(indexed_t);
if (value_t->tag == ListType) {
@@ -877,8 +893,7 @@ type_t *get_type(env_t *env, ast_t *ast)
code_err(indexing->index, "I only know how to index lists using integers, not ", type_to_str(index_t));
} else if (value_t->tag == TableType) {
DeclareMatch(table_type, value_t, TableType);
- if (table_type->default_value)
- return table_type->value_type;
+ if (table_type->default_value) return table_type->value_type;
return Type(OptionalType, table_type->value_type);
} else if (value_t->tag == TextType) {
return value_t;
@@ -889,26 +904,25 @@ type_t *get_type(env_t *env, ast_t *ast)
case FunctionCall: {
DeclareMatch(call, ast, FunctionCall);
type_t *fn_type_t = get_type(env, call->fn);
- if (!fn_type_t)
- code_err(call->fn, "I couldn't find this function");
+ if (!fn_type_t) code_err(call->fn, "I couldn't find this function");
if (fn_type_t->tag == TypeInfoType) {
type_t *t = Match(fn_type_t, TypeInfoType)->type;
- binding_t *constructor = get_constructor(env, t, call->args, env->current_type != NULL && type_eq(env->current_type, t));
- if (constructor)
- return t;
+ binding_t *constructor =
+ get_constructor(env, t, call->args, env->current_type != NULL && type_eq(env->current_type, t));
+ if (constructor) return t;
else if (t->tag == StructType || t->tag == IntType || t->tag == BigIntType || t->tag == NumType
- || t->tag == ByteType || t->tag == TextType || t->tag == CStringType)
+ || t->tag == ByteType || t->tag == TextType || t->tag == CStringType)
return t; // Constructor
arg_t *arg_types = NULL;
for (arg_ast_t *arg = call->args; arg; arg = arg->next)
- arg_types = new(arg_t, .type=get_type(env, arg->value), .name=arg->name, .next=arg_types);
+ arg_types = new (arg_t, .type = get_type(env, arg->value), .name = arg->name, .next = arg_types);
REVERSE_LIST(arg_types);
- code_err(call->fn, "I couldn't find a type constructor for ", type_to_text(Type(FunctionType, .args=arg_types, .ret=t)));
+ code_err(call->fn, "I couldn't find a type constructor for ",
+ type_to_text(Type(FunctionType, .args = arg_types, .ret = t)));
}
- if (fn_type_t->tag == ClosureType)
- fn_type_t = Match(fn_type_t, ClosureType)->fn;
+ if (fn_type_t->tag == ClosureType) fn_type_t = Match(fn_type_t, ClosureType)->fn;
if (fn_type_t->tag != FunctionType)
code_err(call->fn, "This isn't a function, it's a ", type_to_str(fn_type_t));
DeclareMatch(fn_type, fn_type_t, FunctionType);
@@ -925,8 +939,10 @@ type_t *get_type(env_t *env, ast_t *ast)
self_value_t = value_type(self_value_t);
if (self_value_t->tag == TypeInfoType || self_value_t->tag == ModuleType) {
- return get_type(env, WrapAST(ast, FunctionCall, .fn=WrapAST(call->self, FieldAccess, .fielded=call->self, .field=call->name),
- .args=call->args));
+ return get_type(env,
+ WrapAST(ast, FunctionCall,
+ .fn = WrapAST(call->self, FieldAccess, .fielded = call->self, .field = call->name),
+ .args = call->args));
}
switch (self_value_t->tag) {
@@ -935,17 +951,17 @@ type_t *get_type(env_t *env, ast_t *ast)
if (streq(call->name, "binary_search")) return INT_TYPE;
else if (streq(call->name, "by")) return self_value_t;
else if (streq(call->name, "clear")) return Type(VoidType);
- else if (streq(call->name, "counts")) return Type(TableType, .key_type=item_type, .value_type=INT_TYPE);
- else if (streq(call->name, "find")) return Type(OptionalType, .type=INT_TYPE);
- else if (streq(call->name, "where")) return Type(OptionalType, .type=INT_TYPE);
+ else if (streq(call->name, "counts")) return Type(TableType, .key_type = item_type, .value_type = INT_TYPE);
+ else if (streq(call->name, "find")) return Type(OptionalType, .type = INT_TYPE);
+ else if (streq(call->name, "where")) return Type(OptionalType, .type = INT_TYPE);
else if (streq(call->name, "from")) return self_value_t;
else if (streq(call->name, "has")) return Type(BoolType);
- else if (streq(call->name, "heap_pop")) return Type(OptionalType, .type=item_type);
+ else if (streq(call->name, "heap_pop")) return Type(OptionalType, .type = item_type);
else if (streq(call->name, "heap_push")) return Type(VoidType);
else if (streq(call->name, "heapify")) return Type(VoidType);
else if (streq(call->name, "insert")) return Type(VoidType);
else if (streq(call->name, "insert_all")) return Type(VoidType);
- else if (streq(call->name, "pop")) return Type(OptionalType, .type=item_type);
+ else if (streq(call->name, "pop")) return Type(OptionalType, .type = item_type);
else if (streq(call->name, "random")) return item_type;
else if (streq(call->name, "remove_at")) return Type(VoidType);
else if (streq(call->name, "remove_item")) return Type(VoidType);
@@ -957,7 +973,7 @@ type_t *get_type(env_t *env, ast_t *ast)
else if (streq(call->name, "sort")) return Type(VoidType);
else if (streq(call->name, "sorted")) return self_value_t;
else if (streq(call->name, "to")) return self_value_t;
- else if (streq(call->name, "unique")) return Type(SetType, .item_type=item_type);
+ else if (streq(call->name, "unique")) return Type(SetType, .item_type = item_type);
else code_err(ast, "There is no '", call->name, "' method for lists");
}
case SetType: {
@@ -977,7 +993,7 @@ type_t *get_type(env_t *env, ast_t *ast)
case TableType: {
DeclareMatch(table, self_value_t, TableType);
if (streq(call->name, "clear")) return Type(VoidType);
- else if (streq(call->name, "get")) return Type(OptionalType, .type=table->value_type);
+ else if (streq(call->name, "get")) return Type(OptionalType, .type = table->value_type);
else if (streq(call->name, "get_or_set")) return table->value_type;
else if (streq(call->name, "has")) return Type(BoolType);
else if (streq(call->name, "remove")) return Type(VoidType);
@@ -989,19 +1005,17 @@ type_t *get_type(env_t *env, ast_t *ast)
default: {
if (call->name[0] == '_') {
if (env->current_type == NULL || !type_eq(env->current_type, self_value_t))
- code_err(ast, "You can't call private methods starting with underscore (like '", call->name, "') "
- "outside of the place where the type (", type_to_text(self_value_t), ") is defined.");
+ code_err(ast, "You can't call private methods starting with underscore (like '", call->name,
+ "') "
+ "outside of the place where the type (",
+ type_to_text(self_value_t), ") is defined.");
}
type_t *field_type = get_field_type(self_value_t, call->name);
- if (field_type && field_type->tag == ClosureType)
- field_type = Match(field_type, ClosureType)->fn;
- if (field_type && field_type->tag == FunctionType)
- return Match(field_type, FunctionType)->ret;
+ if (field_type && field_type->tag == ClosureType) field_type = Match(field_type, ClosureType)->fn;
+ if (field_type && field_type->tag == FunctionType) return Match(field_type, FunctionType)->ret;
type_t *fn_type_t = get_method_type(env, call->self, call->name);
- if (!fn_type_t)
- code_err(ast, "No such method!");
- if (fn_type_t->tag != FunctionType)
- code_err(ast, "This isn't a method, it's a ", type_to_str(fn_type_t));
+ if (!fn_type_t) code_err(ast, "No such method!");
+ if (fn_type_t->tag != FunctionType) code_err(ast, "This isn't a method, it's a ", type_to_str(fn_type_t));
DeclareMatch(fn_type, fn_type_t, FunctionType);
return fn_type->ret;
}
@@ -1010,15 +1024,21 @@ type_t *get_type(env_t *env, ast_t *ast)
case Block: {
DeclareMatch(block, ast, Block);
ast_list_t *last = block->statements;
- if (!last)
- return Type(VoidType);
+ if (!last) return Type(VoidType);
while (last->next)
last = last->next;
// Early out if the type is knowable without any context from the block:
switch (last->ast->tag) {
- case UPDATE_CASES: case Assign: case Declare: case FunctionDef: case ConvertDef: case StructDef: case EnumDef: case LangDef: case Extend:
- return Type(VoidType);
+ case UPDATE_CASES:
+ case Assign:
+ case Declare:
+ case FunctionDef:
+ case ConvertDef:
+ case StructDef:
+ case EnumDef:
+ case LangDef:
+ case Extend: return Type(VoidType);
default: break;
}
@@ -1030,10 +1050,13 @@ type_t *get_type(env_t *env, ast_t *ast)
bind_statement(block_env, stmt->ast);
if (stmt->next) { // Check for unreachable code:
if (stmt->ast->tag == Return)
- code_err(stmt->ast, "This statement will always return, so the rest of the code in this block is unreachable!");
+ code_err(
+ stmt->ast,
+ "This statement will always return, so the rest of the code in this block is unreachable!");
type_t *statement_type = get_type(block_env, stmt->ast);
if (statement_type && statement_type->tag == AbortType && stmt->next)
- code_err(stmt->ast, "This statement will always abort, so the rest of the code in this block is unreachable!");
+ code_err(stmt->ast,
+ "This statement will always abort, so the rest of the code in this block is unreachable!");
}
}
return get_type(block_env, last->ast);
@@ -1041,7 +1064,11 @@ type_t *get_type(env_t *env, ast_t *ast)
case Extern: {
return parse_type_ast(env, Match(ast, Extern)->type);
}
- case Declare: case Assign: case UPDATE_CASES: case DocTest: case Assert: {
+ case Declare:
+ case Assign:
+ case UPDATE_CASES:
+ case DocTest:
+ case Assert: {
return Type(VoidType);
}
case Use: {
@@ -1052,50 +1079,46 @@ type_t *get_type(env_t *env, ast_t *ast)
Path_t used_path = Path$resolved(Path$from_str(Match(ast, Use)->path), source_dir);
return Type(ModuleType, Path$as_c_string(used_path));
}
- default:
- return Type(ModuleType, Match(ast, Use)->path);
+ default: return Type(ModuleType, Match(ast, Use)->path);
}
}
case Return: {
ast_t *val = Match(ast, Return)->value;
- if (env->fn_ret)
- env = with_enum_scope(env, env->fn_ret);
- return Type(ReturnType, .ret=(val ? get_type(env, val) : Type(VoidType)));
+ if (env->fn_ret) env = with_enum_scope(env, env->fn_ret);
+ return Type(ReturnType, .ret = (val ? get_type(env, val) : Type(VoidType)));
}
- case Stop: case Skip: {
+ case Stop:
+ case Skip: {
return Type(AbortType);
}
- case Pass: case Defer: return Type(VoidType);
+ case Pass:
+ case Defer: return Type(VoidType);
case Negative: {
ast_t *value = Match(ast, Negative)->value;
type_t *t = get_type(env, value);
- if (t->tag == IntType || t->tag == NumType)
- return t;
+ if (t->tag == IntType || t->tag == NumType) return t;
binding_t *b = get_namespace_binding(env, value, "negative");
if (b && b->type->tag == FunctionType) {
DeclareMatch(fn, b->type, FunctionType);
- if (fn->args && type_eq(t, get_arg_type(env, fn->args)) && type_eq(t, fn->ret))
- return t;
+ if (fn->args && type_eq(t, get_arg_type(env, fn->args)) && type_eq(t, fn->ret)) return t;
}
code_err(ast, "I don't know how to get the negative value of type ", type_to_str(t));
}
case Not: {
type_t *t = get_type(env, Match(ast, Not)->value);
- if (t->tag == IntType || t->tag == NumType || t->tag == BoolType)
- return t;
- if (t->tag == OptionalType)
- return Type(BoolType);
+ if (t->tag == IntType || t->tag == NumType || t->tag == BoolType) return t;
+ if (t->tag == OptionalType) return Type(BoolType);
ast_t *value = Match(ast, Not)->value;
binding_t *b = get_namespace_binding(env, value, "negated");
if (b && b->type->tag == FunctionType) {
DeclareMatch(fn, b->type, FunctionType);
- if (fn->args && type_eq(t, get_arg_type(env, fn->args)) && type_eq(t, fn->ret))
- return t;
+ if (fn->args && type_eq(t, get_arg_type(env, fn->args)) && type_eq(t, fn->ret)) return t;
}
- code_err(ast, "I only know how to get 'not' of boolean, numeric, and optional pointer types, not ", type_to_str(t));
+ code_err(ast, "I only know how to get 'not' of boolean, numeric, and optional pointer types, not ",
+ type_to_str(t));
}
case Or: {
binary_operands_t binop = BINARY_OPERANDS(ast);
@@ -1103,13 +1126,10 @@ type_t *get_type(env_t *env, ast_t *ast)
type_t *rhs_t = get_type(env, binop.rhs);
type_t *lhs_val = value_type(lhs_t), *rhs_val = value_type(rhs_t);
- if (type_eq(lhs_val, rhs_val) && lhs_val->tag == SetType)
- return lhs_val;
+ if (type_eq(lhs_val, rhs_val) && lhs_val->tag == SetType) return lhs_val;
- if (binop.lhs->tag == Int && is_int_type(rhs_t))
- return rhs_t;
- else if (binop.rhs->tag == Int && is_int_type(lhs_t))
- return lhs_t;
+ if (binop.lhs->tag == Int && is_int_type(rhs_t)) return rhs_t;
+ else if (binop.rhs->tag == Int && is_int_type(lhs_t)) return lhs_t;
// `opt? or (x == y)` / `(x == y) or opt?` is a boolean conditional:
if ((lhs_t->tag == OptionalType && rhs_t->tag == BoolType)
@@ -1126,22 +1146,20 @@ type_t *get_type(env_t *env, ast_t *ast)
if (rhs_t->tag == OptionalType) {
type_t *result = most_complete_type(lhs_t, rhs_t);
if (result == NULL)
- code_err(ast, "I could not determine the type of ", type_to_str(lhs_t), " `or` ", type_to_str(rhs_t));
+ code_err(ast, "I could not determine the type of ", type_to_str(lhs_t), " `or` ",
+ type_to_str(rhs_t));
return result;
} else if (rhs_t->tag == AbortType || rhs_t->tag == ReturnType) {
return Match(lhs_t, OptionalType)->type;
}
type_t *non_opt = Match(lhs_t, OptionalType)->type;
non_opt = most_complete_type(non_opt, rhs_t);
- if (non_opt != NULL)
- return non_opt;
+ if (non_opt != NULL) return non_opt;
} else if ((is_numeric_type(lhs_t) || lhs_t->tag == BoolType)
- && (is_numeric_type(rhs_t) || rhs_t->tag == BoolType)
- && lhs_t->tag != NumType && rhs_t->tag != NumType) {
- if (can_compile_to_type(env, binop.rhs, lhs_t))
- return lhs_t;
- else if (can_compile_to_type(env, binop.lhs, rhs_t))
- return rhs_t;
+ && (is_numeric_type(rhs_t) || rhs_t->tag == BoolType) && lhs_t->tag != NumType
+ && rhs_t->tag != NumType) {
+ if (can_compile_to_type(env, binop.rhs, lhs_t)) return lhs_t;
+ else if (can_compile_to_type(env, binop.lhs, rhs_t)) return rhs_t;
} else if (lhs_t->tag == SetType && rhs_t->tag == SetType && type_eq(lhs_t, rhs_t)) {
return lhs_t;
}
@@ -1153,13 +1171,10 @@ type_t *get_type(env_t *env, ast_t *ast)
type_t *rhs_t = get_type(env, binop.rhs);
type_t *lhs_val = value_type(lhs_t), *rhs_val = value_type(rhs_t);
- if (type_eq(lhs_val, rhs_val) && lhs_val->tag == SetType)
- return lhs_val;
+ if (type_eq(lhs_val, rhs_val) && lhs_val->tag == SetType) return lhs_val;
- if (binop.lhs->tag == Int && is_int_type(rhs_t))
- return rhs_t;
- else if (binop.rhs->tag == Int && is_int_type(lhs_t))
- return lhs_t;
+ if (binop.lhs->tag == Int && is_int_type(rhs_t)) return rhs_t;
+ else if (binop.rhs->tag == Int && is_int_type(lhs_t)) return lhs_t;
// `and` between optionals/bools is a boolean expression like `if opt? and opt?:` or `if x > 0 and opt?:`
if ((lhs_t->tag == OptionalType || lhs_t->tag == BoolType)
@@ -1173,17 +1188,15 @@ type_t *get_type(env_t *env, ast_t *ast)
}
// Bitwise AND:
- if ((is_numeric_type(lhs_t) || lhs_t->tag == BoolType)
- && (is_numeric_type(rhs_t) || rhs_t->tag == BoolType)
+ if ((is_numeric_type(lhs_t) || lhs_t->tag == BoolType) && (is_numeric_type(rhs_t) || rhs_t->tag == BoolType)
&& lhs_t->tag != NumType && rhs_t->tag != NumType) {
- if (can_compile_to_type(env, binop.rhs, lhs_t))
- return lhs_t;
- else if (can_compile_to_type(env, binop.lhs, rhs_t))
- return rhs_t;
+ if (can_compile_to_type(env, binop.rhs, lhs_t)) return lhs_t;
+ else if (can_compile_to_type(env, binop.lhs, rhs_t)) return rhs_t;
} else if (lhs_t->tag == SetType && rhs_t->tag == SetType && type_eq(lhs_t, rhs_t)) {
return lhs_t;
}
- code_err(ast, "I couldn't figure out how to do `and` between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
+ code_err(ast, "I couldn't figure out how to do `and` between ", type_to_str(lhs_t), " and ",
+ type_to_str(rhs_t));
}
case Xor: {
binary_operands_t binop = BINARY_OPERANDS(ast);
@@ -1191,13 +1204,10 @@ type_t *get_type(env_t *env, ast_t *ast)
type_t *rhs_t = get_type(env, binop.rhs);
type_t *lhs_val = value_type(lhs_t), *rhs_val = value_type(rhs_t);
- if (type_eq(lhs_val, rhs_val) && lhs_val->tag == SetType)
- return lhs_val;
+ if (type_eq(lhs_val, rhs_val) && lhs_val->tag == SetType) return lhs_val;
- if (binop.lhs->tag == Int && is_int_type(rhs_t))
- return rhs_t;
- else if (binop.rhs->tag == Int && is_int_type(lhs_t))
- return lhs_t;
+ if (binop.lhs->tag == Int && is_int_type(rhs_t)) return rhs_t;
+ else if (binop.rhs->tag == Int && is_int_type(lhs_t)) return lhs_t;
// `xor` between optionals/bools is a boolean expression like `if opt? xor opt?:` or `if x > 0 xor opt?:`
if ((lhs_t->tag == OptionalType || lhs_t->tag == BoolType)
@@ -1211,45 +1221,55 @@ type_t *get_type(env_t *env, ast_t *ast)
}
// Bitwise XOR:
- if ((is_numeric_type(lhs_t) || lhs_t->tag == BoolType)
- && (is_numeric_type(rhs_t) || rhs_t->tag == BoolType)
+ if ((is_numeric_type(lhs_t) || lhs_t->tag == BoolType) && (is_numeric_type(rhs_t) || rhs_t->tag == BoolType)
&& lhs_t->tag != NumType && rhs_t->tag != NumType) {
- if (can_compile_to_type(env, binop.rhs, lhs_t))
- return lhs_t;
- else if (can_compile_to_type(env, binop.lhs, rhs_t))
- return rhs_t;
+ if (can_compile_to_type(env, binop.rhs, lhs_t)) return lhs_t;
+ else if (can_compile_to_type(env, binop.lhs, rhs_t)) return rhs_t;
} else if (lhs_t->tag == SetType && rhs_t->tag == SetType && type_eq(lhs_t, rhs_t)) {
return lhs_t;
}
- code_err(ast, "I couldn't figure out how to do `xor` between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
+ code_err(ast, "I couldn't figure out how to do `xor` between ", type_to_str(lhs_t), " and ",
+ type_to_str(rhs_t));
}
case Compare:
- case Equals: case NotEquals: case LessThan: case LessThanOrEquals: case GreaterThan: case GreaterThanOrEquals: {
+ case Equals:
+ case NotEquals:
+ case LessThan:
+ case LessThanOrEquals:
+ case GreaterThan:
+ case GreaterThanOrEquals: {
binary_operands_t binop = BINARY_OPERANDS(ast);
type_t *lhs_t = get_type(env, binop.lhs);
type_t *rhs_t = get_type(env, binop.rhs);
- if ((binop.lhs->tag == Int && is_numeric_type(rhs_t))
- || (binop.rhs->tag == Int && is_numeric_type(lhs_t))
- || can_compile_to_type(env, binop.rhs, lhs_t)
- || can_compile_to_type(env, binop.lhs, rhs_t))
- return ast->tag == Compare ? Type(IntType, .bits=TYPE_IBITS32) : Type(BoolType);
+ if ((binop.lhs->tag == Int && is_numeric_type(rhs_t)) || (binop.rhs->tag == Int && is_numeric_type(lhs_t))
+ || can_compile_to_type(env, binop.rhs, lhs_t) || can_compile_to_type(env, binop.lhs, rhs_t))
+ return ast->tag == Compare ? Type(IntType, .bits = TYPE_IBITS32) : Type(BoolType);
code_err(ast, "I don't know how to compare ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
}
- case Power: case Multiply: case Divide: case Mod: case Mod1: case Plus: case Minus: case LeftShift:
- case UnsignedLeftShift: case RightShift: case UnsignedRightShift: {
+ case Power:
+ case Multiply:
+ case Divide:
+ case Mod:
+ case Mod1:
+ case Plus:
+ case Minus:
+ case LeftShift:
+ case UnsignedLeftShift:
+ case RightShift:
+ case UnsignedRightShift: {
binary_operands_t binop = BINARY_OPERANDS(ast);
type_t *lhs_t = get_type(env, binop.lhs);
type_t *rhs_t = get_type(env, binop.rhs);
if (ast->tag == Minus) {
type_t *lhs_val = value_type(lhs_t), *rhs_val = value_type(rhs_t);
- if (type_eq(lhs_val, rhs_val) && lhs_val->tag == SetType)
- return lhs_val;
+ if (type_eq(lhs_val, rhs_val) && lhs_val->tag == SetType) return lhs_val;
}
- if (ast->tag == LeftShift || ast->tag == UnsignedLeftShift || ast->tag == RightShift || ast->tag == UnsignedRightShift) {
+ if (ast->tag == LeftShift || ast->tag == UnsignedLeftShift || ast->tag == RightShift
+ || ast->tag == UnsignedRightShift) {
if (!is_int_type(rhs_t))
code_err(binop.rhs, "I only know how to do bit shifting by integer amounts, not ", type_to_str(rhs_t));
}
@@ -1279,9 +1299,8 @@ type_t *get_type(env_t *env, ast_t *ast)
if (b && b->type->tag == FunctionType) {
DeclareMatch(fn, b->type, FunctionType);
if (type_eq(fn->ret, rhs_t)) {
- arg_ast_t *args = new(arg_ast_t, .value=binop.rhs, .next=new(arg_ast_t, .value=binop.lhs));
- if (is_valid_call(env, fn->args, args, true))
- return rhs_t;
+ arg_ast_t *args = new (arg_ast_t, .value = binop.rhs, .next = new (arg_ast_t, .value = binop.lhs));
+ if (is_valid_call(env, fn->args, args, true)) return rhs_t;
}
}
} else if (ast->tag == Multiply && is_numeric_type(rhs_t)) {
@@ -1289,9 +1308,8 @@ type_t *get_type(env_t *env, ast_t *ast)
if (b && b->type->tag == FunctionType) {
DeclareMatch(fn, b->type, FunctionType);
if (type_eq(fn->ret, lhs_t)) {
- arg_ast_t *args = new(arg_ast_t, .value=binop.lhs, .next=new(arg_ast_t, .value=binop.rhs));
- if (is_valid_call(env, fn->args, args, true))
- return lhs_t;
+ arg_ast_t *args = new (arg_ast_t, .value = binop.lhs, .next = new (arg_ast_t, .value = binop.rhs));
+ if (is_valid_call(env, fn->args, args, true)) return lhs_t;
}
}
} else if ((ast->tag == Divide || ast->tag == Mod || ast->tag == Mod1) && is_numeric_type(rhs_t)) {
@@ -1299,39 +1317,43 @@ type_t *get_type(env_t *env, ast_t *ast)
if (b && b->type->tag == FunctionType) {
DeclareMatch(fn, b->type, FunctionType);
if (type_eq(fn->ret, lhs_t)) {
- arg_ast_t *args = new(arg_ast_t, .value=binop.lhs, .next=new(arg_ast_t, .value=binop.rhs));
- if (is_valid_call(env, fn->args, args, true))
- return lhs_t;
+ arg_ast_t *args = new (arg_ast_t, .value = binop.lhs, .next = new (arg_ast_t, .value = binop.rhs));
+ if (is_valid_call(env, fn->args, args, true)) return lhs_t;
}
}
}
- type_t *overall_t = (can_compile_to_type(env, binop.rhs, lhs_t) ? lhs_t : (can_compile_to_type(env, binop.lhs, rhs_t) ? rhs_t : NULL));
+ type_t *overall_t =
+ (can_compile_to_type(env, binop.rhs, lhs_t) ? lhs_t
+ : (can_compile_to_type(env, binop.lhs, rhs_t) ? rhs_t : NULL));
if (overall_t == NULL)
- code_err(ast, "I don't know how to do math operations between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
+ code_err(ast, "I don't know how to do math operations between ", type_to_str(lhs_t), " and ",
+ type_to_str(rhs_t));
binding_t *b = get_metamethod_binding(env, ast->tag, binop.lhs, binop.rhs, overall_t);
if (b) return overall_t;
- if (is_numeric_type(lhs_t) && is_numeric_type(rhs_t))
- return overall_t;
+ if (is_numeric_type(lhs_t) && is_numeric_type(rhs_t)) return overall_t;
- code_err(ast, "I don't know how to do math operations between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
+ code_err(ast, "I don't know how to do math operations between ", type_to_str(lhs_t), " and ",
+ type_to_str(rhs_t));
}
case Concat: {
binary_operands_t binop = BINARY_OPERANDS(ast);
type_t *lhs_t = get_type(env, binop.lhs);
type_t *rhs_t = get_type(env, binop.rhs);
- type_t *overall_t = (can_compile_to_type(env, binop.rhs, lhs_t) ? lhs_t : (can_compile_to_type(env, binop.lhs, rhs_t) ? rhs_t : NULL));
+ type_t *overall_t =
+ (can_compile_to_type(env, binop.rhs, lhs_t) ? lhs_t
+ : (can_compile_to_type(env, binop.lhs, rhs_t) ? rhs_t : NULL));
if (overall_t == NULL)
- code_err(ast, "I don't know how to do operations between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
+ code_err(ast, "I don't know how to do operations between ", type_to_str(lhs_t), " and ",
+ type_to_str(rhs_t));
binding_t *b = get_metamethod_binding(env, ast->tag, binop.lhs, binop.rhs, overall_t);
if (b) return overall_t;
- if (overall_t->tag == ListType || overall_t->tag == SetType || overall_t->tag == TextType)
- return overall_t;
+ if (overall_t->tag == ListType || overall_t->tag == SetType || overall_t->tag == TextType) return overall_t;
code_err(ast, "I don't know how to do concatenation between ", type_to_str(lhs_t), " and ", type_to_str(rhs_t));
}
@@ -1341,8 +1363,9 @@ type_t *get_type(env_t *env, ast_t *ast)
type_t *iter_t = get_type(env, reduction->iter);
if (reduction->op == Equals || reduction->op == NotEquals || reduction->op == LessThan
- || reduction->op == LessThanOrEquals || reduction->op == GreaterThan || reduction->op == GreaterThanOrEquals)
- return Type(OptionalType, .type=Type(BoolType));
+ || reduction->op == LessThanOrEquals || reduction->op == GreaterThan
+ || reduction->op == GreaterThanOrEquals)
+ return Type(OptionalType, .type = Type(BoolType));
type_t *iterated = get_iterated_type(iter_t);
if (!iterated)
@@ -1352,10 +1375,11 @@ type_t *get_type(env_t *env, ast_t *ast)
set_binding(item_scope, "$", iterated, EMPTY_TEXT);
iterated = get_type(item_scope, reduction->key);
}
- return iterated->tag == OptionalType ? iterated : Type(OptionalType, .type=iterated);
+ return iterated->tag == OptionalType ? iterated : Type(OptionalType, .type = iterated);
}
- case Min: case Max: {
+ case Min:
+ case Max: {
// Unsafe! These types *should* have the same fields and this saves a lot of duplicate code:
ast_t *lhs = ast->__data.Min.lhs, *rhs = ast->__data.Min.rhs;
// Okay safe again
@@ -1363,7 +1387,8 @@ type_t *get_type(env_t *env, ast_t *ast)
type_t *lhs_t = get_type(env, lhs), *rhs_t = get_type(env, rhs);
type_t *t = type_or_type(lhs_t, rhs_t);
if (!t)
- code_err(ast, "The two sides of this operation are not compatible: ", type_to_str(lhs_t), " vs ", type_to_str(rhs_t));
+ code_err(ast, "The two sides of this operation are not compatible: ", type_to_str(lhs_t), " vs ",
+ type_to_str(rhs_t));
return t;
}
@@ -1373,24 +1398,21 @@ type_t *get_type(env_t *env, ast_t *ast)
env_t *scope = fresh_scope(env); // For now, just use closed variables in scope normally
for (arg_ast_t *arg = lambda->args; arg; arg = arg->next) {
type_t *t = get_arg_ast_type(env, arg);
- args = new(arg_t, .name=arg->name, .type=t, .next=args);
+ args = new (arg_t, .name = arg->name, .type = t, .next = args);
set_binding(scope, arg->name, t, EMPTY_TEXT);
}
REVERSE_LIST(args);
type_t *ret = get_type(scope, lambda->body);
- if (ret->tag == ReturnType)
- ret = Match(ret, ReturnType)->ret;
- if (ret->tag == AbortType)
- ret = Type(VoidType);
+ if (ret->tag == ReturnType) ret = Match(ret, ReturnType)->ret;
+ if (ret->tag == AbortType) ret = Type(VoidType);
if (ret->tag == OptionalType && !Match(ret, OptionalType)->type)
code_err(lambda->body, "This function doesn't return a specific optional type");
if (lambda->ret_type) {
type_t *declared = parse_type_ast(env, lambda->ret_type);
- if (can_promote(ret, declared))
- ret = declared;
+ if (can_promote(ret, declared)) ret = declared;
else
code_err(ast, "This function was declared to return a value of type ", type_to_str(declared),
", but actually returns a value of type ", type_to_str(ret));
@@ -1398,17 +1420,21 @@ type_t *get_type(env_t *env, ast_t *ast)
if (has_stack_memory(ret))
code_err(ast, "Functions can't return stack references because the reference may outlive its stack frame.");
- return Type(ClosureType, Type(FunctionType, .args=args, .ret=ret));
+ return Type(ClosureType, Type(FunctionType, .args = args, .ret = ret));
}
- case FunctionDef: case ConvertDef: case StructDef: case EnumDef: case LangDef: case Extend: {
+ case FunctionDef:
+ case ConvertDef:
+ case StructDef:
+ case EnumDef:
+ case LangDef:
+ case Extend: {
return Type(VoidType);
}
case If: {
DeclareMatch(if_, ast, If);
- if (!if_->else_body)
- return Type(VoidType);
+ if (!if_->else_body) return Type(VoidType);
env_t *truthy_scope = env;
env_t *falsey_scope = env;
@@ -1421,17 +1447,14 @@ type_t *get_type(env_t *env, ast_t *ast)
truthy_scope = fresh_scope(env);
if (condition_type->tag == OptionalType)
- set_binding(truthy_scope, varname,
- Match(condition_type, OptionalType)->type, EMPTY_TEXT);
- else
- set_binding(truthy_scope, varname, condition_type, EMPTY_TEXT);
+ set_binding(truthy_scope, varname, Match(condition_type, OptionalType)->type, EMPTY_TEXT);
+ else set_binding(truthy_scope, varname, condition_type, EMPTY_TEXT);
} else if (if_->condition->tag == Var) {
type_t *condition_type = get_type(env, if_->condition);
if (condition_type->tag == OptionalType) {
truthy_scope = fresh_scope(env);
const char *varname = Match(if_->condition, Var)->name;
- set_binding(truthy_scope, varname,
- Match(condition_type, OptionalType)->type, EMPTY_TEXT);
+ set_binding(truthy_scope, varname, Match(condition_type, OptionalType)->type, EMPTY_TEXT);
}
}
@@ -1439,8 +1462,7 @@ type_t *get_type(env_t *env, ast_t *ast)
type_t *false_t = get_type(falsey_scope, if_->else_body);
type_t *t_either = type_or_type(true_t, false_t);
if (!t_either)
- code_err(if_->else_body,
- "I was expecting this block to have a ", type_to_str(true_t),
+ code_err(if_->else_body, "I was expecting this block to have a ", type_to_str(true_t),
" value (based on earlier clauses), but it actually has a ", type_to_str(false_t), " value.");
return t_either;
}
@@ -1453,15 +1475,13 @@ type_t *get_type(env_t *env, ast_t *ast)
for (when_clause_t *clause = when->clauses; clause; clause = clause->next) {
t = type_or_type(t, get_type(env, clause->body));
}
- if (when->else_body)
- t = type_or_type(t, get_type(env, when->else_body));
- else if (t && t->tag != OptionalType)
- t = Type(OptionalType, .type=t);
+ if (when->else_body) t = type_or_type(t, get_type(env, when->else_body));
+ else if (t && t->tag != OptionalType) t = Type(OptionalType, .type = t);
return t;
}
type_t *overall_t = NULL;
- tag_t * const tags = Match(subject_t, EnumType)->tags;
+ tag_t *const tags = Match(subject_t, EnumType)->tags;
typedef struct match_s {
tag_t *tag;
@@ -1470,22 +1490,19 @@ type_t *get_type(env_t *env, ast_t *ast)
} match_t;
match_t *matches = NULL;
for (tag_t *tag = tags; tag; tag = tag->next)
- matches = new(match_t, .tag=tag, .handled=false, .next=matches);
+ matches = new (match_t, .tag = tag, .handled = false, .next = matches);
for (when_clause_t *clause = when->clauses; clause; clause = clause->next) {
const char *tag_name;
- if (clause->pattern->tag == Var)
- tag_name = Match(clause->pattern, Var)->name;
+ if (clause->pattern->tag == Var) tag_name = Match(clause->pattern, Var)->name;
else if (clause->pattern->tag == FunctionCall && Match(clause->pattern, FunctionCall)->fn->tag == Var)
tag_name = Match(Match(clause->pattern, FunctionCall)->fn, Var)->name;
- else
- code_err(clause->pattern, "This is not a valid pattern for a ", type_to_str(subject_t), " enum");
+ else code_err(clause->pattern, "This is not a valid pattern for a ", type_to_str(subject_t), " enum");
Text_t valid_tags = EMPTY_TEXT;
for (match_t *m = matches; m; m = m->next) {
if (streq(m->tag->name, tag_name)) {
- if (m->handled)
- code_err(clause->pattern, "This tag was already handled earlier");
+ if (m->handled) code_err(clause->pattern, "This tag was already handled earlier");
m->handled = true;
goto found_matching_tag;
}
@@ -1493,9 +1510,9 @@ type_t *get_type(env_t *env, ast_t *ast)
valid_tags = Texts(valid_tags, m->tag->name);
}
- code_err(clause->pattern, "There is no tag '", tag_name,
- "' for the type ", type_to_str(subject_t), " (valid tags: ", valid_tags, ")");
- found_matching_tag:;
+ code_err(clause->pattern, "There is no tag '", tag_name, "' for the type ", type_to_str(subject_t),
+ " (valid tags: ", valid_tags, ")");
+ found_matching_tag:;
}
for (when_clause_t *clause = when->clauses; clause; clause = clause->next) {
@@ -1524,27 +1541,27 @@ type_t *get_type(env_t *env, ast_t *ast)
type_t *else_t = get_type(env, when->else_body);
type_t *merged = type_or_type(overall_t, else_t);
if (!merged)
- code_err(when->else_body,
- "I was expecting this block to have a ", type_to_str(overall_t),
+ code_err(when->else_body, "I was expecting this block to have a ", type_to_str(overall_t),
" value (based on earlier clauses), but it actually has a ", type_to_str(else_t), " value.");
return merged;
} else {
Text_t unhandled = EMPTY_TEXT;
for (match_t *m = matches; m; m = m->next) {
if (!m->handled)
- unhandled = unhandled.length > 0 ? Texts(unhandled, ", ", m->tag->name) : Text$from_str(m->tag->name);
+ unhandled =
+ unhandled.length > 0 ? Texts(unhandled, ", ", m->tag->name) : Text$from_str(m->tag->name);
}
- if (unhandled.length > 0)
- code_err(ast, "This 'when' statement doesn't handle the tags: ", unhandled);
+ if (unhandled.length > 0) code_err(ast, "This 'when' statement doesn't handle the tags: ", unhandled);
return overall_t;
}
}
- case While: case Repeat: case For: return Type(VoidType);
+ case While:
+ case Repeat:
+ case For: return Type(VoidType);
case InlineCCode: {
DeclareMatch(inline_code, ast, InlineCCode);
- if (inline_code->type)
- return inline_code->type;
+ if (inline_code->type) return inline_code->type;
type_ast_t *type_ast = inline_code->type_ast;
return type_ast ? parse_type_ast(env, type_ast) : Type(VoidType);
}
@@ -1559,35 +1576,37 @@ type_t *get_type(env_t *env, ast_t *ast)
return NULL;
}
-PUREFUNC bool is_discardable(env_t *env, ast_t *ast)
-{
+PUREFUNC bool is_discardable(env_t *env, ast_t *ast) {
switch (ast->tag) {
- case UPDATE_CASES: case Assign: case Declare: case FunctionDef: case ConvertDef: case StructDef: case EnumDef:
- case LangDef: case Use: case Extend:
- return true;
+ case UPDATE_CASES:
+ case Assign:
+ case Declare:
+ case FunctionDef:
+ case ConvertDef:
+ case StructDef:
+ case EnumDef:
+ case LangDef:
+ case Use:
+ case Extend: return true;
default: break;
}
type_t *t = get_type(env, ast);
return (t->tag == VoidType || t->tag == AbortType || t->tag == ReturnType);
}
-type_t *get_arg_ast_type(env_t *env, arg_ast_t *arg)
-{
+type_t *get_arg_ast_type(env_t *env, arg_ast_t *arg) {
assert(arg->type || arg->value);
- if (arg->type)
- return parse_type_ast(env, arg->type);
+ if (arg->type) return parse_type_ast(env, arg->type);
return get_type(env, arg->value);
}
-type_t *get_arg_type(env_t *env, arg_t *arg)
-{
+type_t *get_arg_type(env_t *env, arg_t *arg) {
assert(arg->type || arg->default_val);
if (arg->type) return arg->type;
return get_type(env, arg->default_val);
}
-static Table_t *get_arg_bindings_with_promotion(env_t *env, arg_t *spec_args, arg_ast_t *call_args)
-{
+static Table_t *get_arg_bindings_with_promotion(env_t *env, arg_t *spec_args, arg_ast_t *call_args) {
Table_t used_args = {};
// Populate keyword args:
@@ -1597,13 +1616,12 @@ static Table_t *get_arg_bindings_with_promotion(env_t *env, arg_t *spec_args, ar
for (arg_t *spec_arg = spec_args; spec_arg; spec_arg = spec_arg->next) {
if (!streq(call_arg->name, spec_arg->name)) continue;
type_t *spec_type = get_arg_type(env, spec_arg);
- if (!can_compile_to_type(env, call_arg->value, spec_type))
- return NULL;
+ if (!can_compile_to_type(env, call_arg->value, spec_type)) return NULL;
Table$str_set(&used_args, call_arg->name, call_arg);
goto next_call_arg;
}
return NULL;
- next_call_arg:;
+ next_call_arg:;
}
arg_ast_t *unused_args = call_args;
@@ -1615,34 +1633,31 @@ static Table_t *get_arg_bindings_with_promotion(env_t *env, arg_t *spec_args, ar
for (; unused_args; unused_args = unused_args->next) {
if (unused_args->name) continue; // Already handled the keyword args
if (!can_compile_to_type(env, unused_args->value, spec_type))
- return NULL; // Positional arg trying to fill in
+ return NULL; // Positional arg trying to fill in
Table$str_set(&used_args, spec_arg->name, unused_args);
unused_args = unused_args->next;
goto found_it;
}
- if (spec_arg->default_val)
- goto found_it;
+ if (spec_arg->default_val) goto found_it;
return NULL;
- found_it: continue;
+ found_it:
+ continue;
}
while (unused_args && unused_args->name)
unused_args = unused_args->next;
- if (unused_args != NULL)
- return NULL;
+ if (unused_args != NULL) return NULL;
- Table_t *ret = new(Table_t);
+ Table_t *ret = new (Table_t);
*ret = used_args;
return ret;
}
-Table_t *get_arg_bindings(env_t *env, arg_t *spec_args, arg_ast_t *call_args, bool promotion_allowed)
-{
- if (promotion_allowed)
- return get_arg_bindings_with_promotion(env, spec_args, call_args);
+Table_t *get_arg_bindings(env_t *env, arg_t *spec_args, arg_ast_t *call_args, bool promotion_allowed) {
+ if (promotion_allowed) return get_arg_bindings_with_promotion(env, spec_args, call_args);
Table_t used_args = {};
@@ -1654,15 +1669,15 @@ Table_t *get_arg_bindings(env_t *env, arg_t *spec_args, arg_ast_t *call_args, bo
for (arg_t *spec_arg = spec_args; spec_arg; spec_arg = spec_arg->next) {
if (!streq(call_arg->name, spec_arg->name)) continue;
type_t *spec_type = get_arg_type(env, spec_arg);
- type_t *complete_call_type = is_incomplete_type(call_type) ? most_complete_type(call_type, spec_type) : call_type;
+ type_t *complete_call_type =
+ is_incomplete_type(call_type) ? most_complete_type(call_type, spec_type) : call_type;
if (!complete_call_type) return NULL;
- if (!type_eq(complete_call_type, spec_type))
- return NULL;
+ if (!type_eq(complete_call_type, spec_type)) return NULL;
Table$str_set(&used_args, call_arg->name, call_arg);
goto next_call_arg;
}
return NULL;
- next_call_arg:;
+ next_call_arg:;
}
arg_ast_t *unused_args = call_args;
@@ -1674,41 +1689,38 @@ Table_t *get_arg_bindings(env_t *env, arg_t *spec_args, arg_ast_t *call_args, bo
for (; unused_args; unused_args = unused_args->next) {
if (unused_args->name) continue; // Already handled the keyword args
type_t *call_type = get_arg_ast_type(env, unused_args);
- type_t *complete_call_type = is_incomplete_type(call_type) ? most_complete_type(call_type, spec_type) : call_type;
+ type_t *complete_call_type =
+ is_incomplete_type(call_type) ? most_complete_type(call_type, spec_type) : call_type;
if (!complete_call_type) return NULL;
- if (!type_eq(complete_call_type, spec_type))
- return NULL; // Positional arg trying to fill in
+ if (!type_eq(complete_call_type, spec_type)) return NULL; // Positional arg trying to fill in
Table$str_set(&used_args, spec_arg->name, unused_args);
unused_args = unused_args->next;
goto found_it;
}
- if (spec_arg->default_val)
- goto found_it;
+ if (spec_arg->default_val) goto found_it;
return NULL;
- found_it: continue;
+ found_it:
+ continue;
}
while (unused_args && unused_args->name)
unused_args = unused_args->next;
- if (unused_args != NULL)
- return NULL;
+ if (unused_args != NULL) return NULL;
- Table_t *ret = new(Table_t);
+ Table_t *ret = new (Table_t);
*ret = used_args;
return ret;
}
-bool is_valid_call(env_t *env, arg_t *spec_args, arg_ast_t *call_args, bool promotion_allowed)
-{
+bool is_valid_call(env_t *env, arg_t *spec_args, arg_ast_t *call_args, bool promotion_allowed) {
Table_t *arg_bindings = get_arg_bindings(env, spec_args, call_args, promotion_allowed);
return (arg_bindings != NULL);
}
-PUREFUNC bool can_be_mutated(env_t *env, ast_t *ast)
-{
+PUREFUNC bool can_be_mutated(env_t *env, ast_t *ast) {
switch (ast->tag) {
case Var: return true;
case InlineCCode: return true;
@@ -1733,16 +1745,16 @@ PUREFUNC bool can_be_mutated(env_t *env, ast_t *ast)
}
}
-type_t *parse_type_string(env_t *env, const char *str)
-{
+type_t *parse_type_string(env_t *env, const char *str) {
type_ast_t *ast = parse_type_str(str);
return ast ? parse_type_ast(env, ast) : NULL;
}
-PUREFUNC bool is_constant(env_t *env, ast_t *ast)
-{
+PUREFUNC bool is_constant(env_t *env, ast_t *ast) {
switch (ast->tag) {
- case Bool: case Num: case None: return true;
+ case Bool:
+ case Num:
+ case None: return true;
case Int: {
DeclareMatch(info, ast, Int);
Int_t int_val = Int$parse(Text$from_str(info->str), NULL);
@@ -1751,17 +1763,16 @@ PUREFUNC bool is_constant(env_t *env, ast_t *ast)
}
case TextJoin: {
DeclareMatch(text, ast, TextJoin);
- if (!text->children) return true; // Empty string, OK
+ if (!text->children) return true; // Empty string, OK
if (text->children->next) return false; // Concatenation, not constant
return is_constant(env, text->children->ast);
}
case TextLiteral: {
- Text_t literal = Match(ast, TextLiteral)->text;
+ Text_t literal = Match(ast, TextLiteral)->text;
TextIter_t state = NEW_TEXT_ITER_STATE(literal);
for (int64_t i = 0; i < literal.length; i++) {
int32_t g = Text$get_grapheme_fast(&state, i);
- if (g < 0 || g > 127 || !isascii(g))
- return false;
+ if (g < 0 || g > 127 || !isascii(g)) return false;
}
return true; // Literal ASCII string, OK
}
@@ -1770,10 +1781,12 @@ PUREFUNC bool is_constant(env_t *env, ast_t *ast)
case BINOP_CASES: {
binary_operands_t binop = BINARY_OPERANDS(ast);
switch (ast->tag) {
- case Power: case Concat: case Min: case Max: case Compare:
- return false;
- default:
- return is_constant(env, binop.lhs) && is_constant(env, binop.rhs);
+ case Power:
+ case Concat:
+ case Min:
+ case Max:
+ case Compare: return false;
+ default: return is_constant(env, binop.lhs) && is_constant(env, binop.rhs);
}
}
case Use: return true;
@@ -1783,39 +1796,32 @@ PUREFUNC bool is_constant(env_t *env, ast_t *ast)
}
}
-PUREFUNC bool can_compile_to_type(env_t *env, ast_t *ast, type_t *needed)
-{
- if (is_incomplete_type(needed))
- return false;
+PUREFUNC bool can_compile_to_type(env_t *env, ast_t *ast, type_t *needed) {
+ if (is_incomplete_type(needed)) return false;
- if (needed->tag == OptionalType && ast->tag == None)
- return true;
+ if (needed->tag == OptionalType && ast->tag == None) return true;
type_t *actual = get_type(env, ast);
- if (actual->tag == OptionalType && needed->tag == OptionalType)
- return can_promote(actual, needed);
+ if (actual->tag == OptionalType && needed->tag == OptionalType) return can_promote(actual, needed);
needed = non_optional(needed);
if (needed->tag == ListType && ast->tag == List) {
type_t *item_type = Match(needed, ListType)->item_type;
for (ast_list_t *item = Match(ast, List)->items; item; item = item->next) {
- if (!can_compile_to_type(env, item->ast, item_type))
- return false;
+ if (!can_compile_to_type(env, item->ast, item_type)) return false;
}
return true;
} else if (needed->tag == SetType && ast->tag == Set) {
type_t *item_type = Match(needed, SetType)->item_type;
for (ast_list_t *item = Match(ast, Set)->items; item; item = item->next) {
- if (!can_compile_to_type(env, item->ast, item_type))
- return false;
+ if (!can_compile_to_type(env, item->ast, item_type)) return false;
}
return true;
} else if (needed->tag == TableType && ast->tag == Table) {
type_t *key_type = Match(needed, TableType)->key_type;
type_t *value_type = Match(needed, TableType)->value_type;
for (ast_list_t *entry = Match(ast, Table)->entries; entry; entry = entry->next) {
- if (entry->ast->tag != TableEntry)
- continue; // TODO: fix this
+ if (entry->ast->tag != TableEntry) continue; // TODO: fix this
DeclareMatch(e, entry->ast, TableEntry);
if (!can_compile_to_type(env, e->key, key_type) || !can_compile_to_type(env, e->value, value_type))
return false;
@@ -1827,8 +1833,7 @@ PUREFUNC bool can_compile_to_type(env_t *env, ast_t *ast, type_t *needed)
return !ptr->is_stack && can_compile_to_type(env, Match(ast, HeapAllocate)->value, ptr->pointed);
else if (ast->tag == StackReference)
return ptr->is_stack && can_compile_to_type(env, Match(ast, StackReference)->value, ptr->pointed);
- else
- return can_promote(actual, needed);
+ else return can_promote(actual, needed);
} else if (actual->tag == OptionalType && needed->tag != OptionalType) {
return false;
} else {
diff --git a/src/types.c b/src/types.c
index 3e39c682..e60483aa 100644
--- a/src/types.c
+++ b/src/types.c
@@ -13,92 +13,84 @@
#include "types.h"
Text_t type_to_text(type_t *t) {
- if (!t)
- return Text("(Unknown type)");
+ if (!t) return Text("(Unknown type)");
switch (t->tag) {
- case UnknownType: return Text("???");
- case AbortType: return Text("Abort");
- case ReturnType: {
- type_t *ret = Match(t, ReturnType)->ret;
- return Texts("Return(", ret ? type_to_text(ret) : Text("Void"), ")");
- }
- case VoidType: return Text("Void");
- case MemoryType: return Text("Memory");
- case BoolType: return Text("Bool");
- case ByteType: return Text("Byte");
- case CStringType: return Text("CString");
- case TextType: return Match(t, TextType)->lang ? Text$from_str(Match(t, TextType)->lang) : Text("Text");
- case BigIntType: return Text("Int");
- case IntType: return Texts("Int", String(Match(t, IntType)->bits));
- case NumType: return Match(t, NumType)->bits == TYPE_NBITS32 ? Text("Num32") : Text("Num");
- case ListType: {
- DeclareMatch(list, t, ListType);
- return Texts("[", type_to_text(list->item_type), "]");
- }
- case TableType: {
- DeclareMatch(table, t, TableType);
- return Texts("{", type_to_text(table->key_type), "=", type_to_text(table->value_type), "}");
- }
- case SetType: {
- DeclareMatch(set, t, SetType);
- return Texts("{", type_to_text(set->item_type), "}");
- }
- case ClosureType: {
- return type_to_text(Match(t, ClosureType)->fn);
- }
- case FunctionType: {
- Text_t c = Text("func(");
- DeclareMatch(fn, t, FunctionType);
- for (arg_t *arg = fn->args; arg; arg = arg->next) {
- c = Texts(c, type_to_text(arg->type));
- if (arg->next) c = Texts(c, ",");
- }
- if (fn->ret && fn->ret->tag != VoidType)
- c = Texts(c, fn->args ? " -> " : "-> ", type_to_text(fn->ret));
- c = Texts(c, ")");
- return c;
- }
- case StructType: {
- DeclareMatch(struct_, t, StructType);
- return Text$from_str(struct_->name);
- }
- case PointerType: {
- DeclareMatch(ptr, t, PointerType);
- Text_t sigil = ptr->is_stack ? Text("&") : Text("@");
- return Texts(sigil, type_to_text(ptr->pointed));
- }
- case EnumType: {
- DeclareMatch(tagged, t, EnumType);
- return Text$from_str(tagged->name);
- }
- case OptionalType: {
- type_t *opt = Match(t, OptionalType)->type;
- if (opt)
- return Texts(type_to_text(opt), "?");
- else
- return Text("(Unknown optional type)");
- }
- case TypeInfoType: {
- return Texts("Type$info(", Match(t, TypeInfoType)->name, ")");
- }
- case ModuleType: {
- return Texts("Module(", Match(t, ModuleType)->name, ")");
- }
- default: {
- raise(SIGABRT);
- return Texts("Unknown type: ", String(t->tag));
+ case UnknownType: return Text("???");
+ case AbortType: return Text("Abort");
+ case ReturnType: {
+ type_t *ret = Match(t, ReturnType)->ret;
+ return Texts("Return(", ret ? type_to_text(ret) : Text("Void"), ")");
+ }
+ case VoidType: return Text("Void");
+ case MemoryType: return Text("Memory");
+ case BoolType: return Text("Bool");
+ case ByteType: return Text("Byte");
+ case CStringType: return Text("CString");
+ case TextType: return Match(t, TextType)->lang ? Text$from_str(Match(t, TextType)->lang) : Text("Text");
+ case BigIntType: return Text("Int");
+ case IntType: return Texts("Int", String(Match(t, IntType)->bits));
+ case NumType: return Match(t, NumType)->bits == TYPE_NBITS32 ? Text("Num32") : Text("Num");
+ case ListType: {
+ DeclareMatch(list, t, ListType);
+ return Texts("[", type_to_text(list->item_type), "]");
+ }
+ case TableType: {
+ DeclareMatch(table, t, TableType);
+ return Texts("{", type_to_text(table->key_type), "=", type_to_text(table->value_type), "}");
+ }
+ case SetType: {
+ DeclareMatch(set, t, SetType);
+ return Texts("{", type_to_text(set->item_type), "}");
+ }
+ case ClosureType: {
+ return type_to_text(Match(t, ClosureType)->fn);
+ }
+ case FunctionType: {
+ Text_t c = Text("func(");
+ DeclareMatch(fn, t, FunctionType);
+ for (arg_t *arg = fn->args; arg; arg = arg->next) {
+ c = Texts(c, type_to_text(arg->type));
+ if (arg->next) c = Texts(c, ",");
}
+ if (fn->ret && fn->ret->tag != VoidType) c = Texts(c, fn->args ? " -> " : "-> ", type_to_text(fn->ret));
+ c = Texts(c, ")");
+ return c;
+ }
+ case StructType: {
+ DeclareMatch(struct_, t, StructType);
+ return Text$from_str(struct_->name);
+ }
+ case PointerType: {
+ DeclareMatch(ptr, t, PointerType);
+ Text_t sigil = ptr->is_stack ? Text("&") : Text("@");
+ return Texts(sigil, type_to_text(ptr->pointed));
+ }
+ case EnumType: {
+ DeclareMatch(tagged, t, EnumType);
+ return Text$from_str(tagged->name);
+ }
+ case OptionalType: {
+ type_t *opt = Match(t, OptionalType)->type;
+ if (opt) return Texts(type_to_text(opt), "?");
+ else return Text("(Unknown optional type)");
+ }
+ case TypeInfoType: {
+ return Texts("Type$info(", Match(t, TypeInfoType)->name, ")");
+ }
+ case ModuleType: {
+ return Texts("Module(", Match(t, ModuleType)->name, ")");
+ }
+ default: {
+ raise(SIGABRT);
+ return Texts("Unknown type: ", String(t->tag));
+ }
}
}
-const char *type_to_str(type_t *t)
-{
- return Text$as_c_string(type_to_text(t));
-}
+const char *type_to_str(type_t *t) { return Text$as_c_string(type_to_text(t)); }
-PUREFUNC const char *get_type_name(type_t *t)
-{
+PUREFUNC const char *get_type_name(type_t *t) {
switch (t->tag) {
case TextType: return Match(t, TextType)->lang;
case StructType: return Match(t, StructType)->name;
@@ -107,8 +99,7 @@ PUREFUNC const char *get_type_name(type_t *t)
}
}
-bool type_eq(type_t *a, type_t *b)
-{
+bool type_eq(type_t *a, type_t *b) {
if (a == b) return true;
if (!a && !b) return true;
if (!a || !b) return false;
@@ -116,11 +107,9 @@ bool type_eq(type_t *a, type_t *b)
return Text$equal_values(type_to_text(a), type_to_text(b));
}
-bool type_is_a(type_t *t, type_t *req)
-{
+bool type_is_a(type_t *t, type_t *req) {
if (type_eq(t, req)) return true;
- if (req->tag == OptionalType && Match(req, OptionalType)->type)
- return type_is_a(t, Match(req, OptionalType)->type);
+ if (req->tag == OptionalType && Match(req, OptionalType)->type) return type_is_a(t, Match(req, OptionalType)->type);
if (t->tag == PointerType && req->tag == PointerType) {
DeclareMatch(t_ptr, t, PointerType);
DeclareMatch(req_ptr, req, PointerType);
@@ -130,20 +119,15 @@ bool type_is_a(type_t *t, type_t *req)
return false;
}
-type_t *non_optional(type_t *t)
-{
- return t->tag == OptionalType ? Match(t, OptionalType)->type : t;
-}
+type_t *non_optional(type_t *t) { return t->tag == OptionalType ? Match(t, OptionalType)->type : t; }
-PUREFUNC type_t *value_type(type_t *t)
-{
+PUREFUNC type_t *value_type(type_t *t) {
while (t->tag == PointerType)
t = Match(t, PointerType)->pointed;
return t;
}
-type_t *type_or_type(type_t *a, type_t *b)
-{
+type_t *type_or_type(type_t *a, type_t *b) {
if (!a) return b;
if (!b) return a;
if (a->tag == OptionalType && !Match(a, OptionalType)->type)
@@ -151,12 +135,10 @@ type_t *type_or_type(type_t *a, type_t *b)
if (b->tag == OptionalType && !Match(b, OptionalType)->type)
return a->tag == OptionalType ? a : Type(OptionalType, a);
if (a->tag == ReturnType && b->tag == ReturnType)
- return Type(ReturnType, .ret=type_or_type(Match(a, ReturnType)->ret, Match(b, ReturnType)->ret));
+ return Type(ReturnType, .ret = type_or_type(Match(a, ReturnType)->ret, Match(b, ReturnType)->ret));
- if (is_incomplete_type(a) && type_eq(b, most_complete_type(a, b)))
- return b;
- if (is_incomplete_type(b) && type_eq(a, most_complete_type(a, b)))
- return a;
+ if (is_incomplete_type(a) && type_eq(b, most_complete_type(a, b))) return b;
+ if (is_incomplete_type(b) && type_eq(a, most_complete_type(a, b))) return a;
if (type_is_a(b, a)) return a;
if (type_is_a(a, b)) return b;
@@ -164,7 +146,8 @@ type_t *type_or_type(type_t *a, type_t *b)
if (b->tag == AbortType || b->tag == ReturnType) return non_optional(a);
if ((a->tag == IntType || a->tag == NumType) && (b->tag == IntType || b->tag == NumType)) {
switch (compare_precision(a, b)) {
- case NUM_PRECISION_EQUAL: case NUM_PRECISION_MORE: return a;
+ case NUM_PRECISION_EQUAL:
+ case NUM_PRECISION_MORE: return a;
case NUM_PRECISION_LESS: return b;
default: return NULL;
}
@@ -173,12 +156,11 @@ type_t *type_or_type(type_t *a, type_t *b)
return NULL;
}
-static PUREFUNC INLINE double type_min_magnitude(type_t *t)
-{
+static PUREFUNC INLINE double type_min_magnitude(type_t *t) {
switch (t->tag) {
case BoolType: return (double)false;
case ByteType: return 0;
- case BigIntType: return -1./0.;
+ case BigIntType: return -1. / 0.;
case IntType: {
switch (Match(t, IntType)->bits) {
case TYPE_IBITS8: return (double)INT8_MIN;
@@ -188,17 +170,16 @@ static PUREFUNC INLINE double type_min_magnitude(type_t *t)
default: errx(1, "Invalid integer bit size");
}
}
- case NumType: return -1./0.;
+ case NumType: return -1. / 0.;
default: return (double)NAN;
}
}
-static PUREFUNC INLINE double type_max_magnitude(type_t *t)
-{
+static PUREFUNC INLINE double type_max_magnitude(type_t *t) {
switch (t->tag) {
case BoolType: return (double)true;
case ByteType: return (double)UINT8_MAX;
- case BigIntType: return 1./0.;
+ case BigIntType: return 1. / 0.;
case IntType: {
switch (Match(t, IntType)->bits) {
case TYPE_IBITS8: return (double)INT8_MAX;
@@ -208,36 +189,28 @@ static PUREFUNC INLINE double type_max_magnitude(type_t *t)
default: errx(1, "Invalid integer bit size");
}
}
- case NumType: return 1./0.;
+ case NumType: return 1. / 0.;
default: return (double)NAN;
}
}
-PUREFUNC precision_cmp_e compare_precision(type_t *a, type_t *b)
-{
- if (a == NULL || b == NULL)
- return NUM_PRECISION_INCOMPARABLE;
+PUREFUNC precision_cmp_e compare_precision(type_t *a, type_t *b) {
+ if (a == NULL || b == NULL) return NUM_PRECISION_INCOMPARABLE;
- if (is_int_type(a) && b->tag == NumType)
- return NUM_PRECISION_LESS;
- else if (a->tag == NumType && is_int_type(b))
- return NUM_PRECISION_MORE;
+ if (is_int_type(a) && b->tag == NumType) return NUM_PRECISION_LESS;
+ else if (a->tag == NumType && is_int_type(b)) return NUM_PRECISION_MORE;
- double a_min = type_min_magnitude(a),
- b_min = type_min_magnitude(b),
- a_max = type_max_magnitude(a),
+ double a_min = type_min_magnitude(a), b_min = type_min_magnitude(b), a_max = type_max_magnitude(a),
b_max = type_max_magnitude(b);
- if (isnan(a_min) || isnan(b_min) || isnan(a_max) || isnan(b_max))
- return NUM_PRECISION_INCOMPARABLE;
+ if (isnan(a_min) || isnan(b_min) || isnan(a_max) || isnan(b_max)) return NUM_PRECISION_INCOMPARABLE;
else if (a_min == b_min && a_max == b_max) return NUM_PRECISION_EQUAL;
else if (a_min <= b_min && b_max <= a_max) return NUM_PRECISION_MORE;
else if (b_min <= a_min && a_max <= b_max) return NUM_PRECISION_LESS;
else return NUM_PRECISION_INCOMPARABLE;
}
-PUREFUNC bool has_heap_memory(type_t *t)
-{
+PUREFUNC bool has_heap_memory(type_t *t) {
switch (t->tag) {
case ListType: return true;
case TableType: return true;
@@ -247,15 +220,13 @@ PUREFUNC bool has_heap_memory(type_t *t)
case BigIntType: return true;
case StructType: {
for (arg_t *field = Match(t, StructType)->fields; field; field = field->next) {
- if (has_heap_memory(field->type))
- return true;
+ if (has_heap_memory(field->type)) return true;
}
return false;
}
case EnumType: {
for (tag_t *tag = Match(t, EnumType)->tags; tag; tag = tag->next) {
- if (tag->type && has_heap_memory(tag->type))
- return true;
+ if (tag->type && has_heap_memory(tag->type)) return true;
}
return false;
}
@@ -263,8 +234,7 @@ PUREFUNC bool has_heap_memory(type_t *t)
}
}
-PUREFUNC bool has_stack_memory(type_t *t)
-{
+PUREFUNC bool has_stack_memory(type_t *t) {
if (!t) return false;
switch (t->tag) {
case PointerType: return Match(t, PointerType)->is_stack;
@@ -273,14 +243,12 @@ PUREFUNC bool has_stack_memory(type_t *t)
}
}
-PUREFUNC const char *enum_single_value_tag(type_t *enum_type, type_t *t)
-{
+PUREFUNC const char *enum_single_value_tag(type_t *enum_type, type_t *t) {
const char *found = NULL;
for (tag_t *tag = Match(enum_type, EnumType)->tags; tag; tag = tag->next) {
if (tag->type->tag != StructType) continue;
DeclareMatch(s, tag->type, StructType);
- if (!s->fields || s->fields->next || !s->fields->type)
- continue;
+ if (!s->fields || s->fields->next || !s->fields->type) continue;
if (can_promote(t, s->fields->type)) {
if (found) // Ambiguous case, multiple matches
@@ -292,51 +260,39 @@ PUREFUNC const char *enum_single_value_tag(type_t *enum_type, type_t *t)
return found;
}
-PUREFUNC bool can_promote(type_t *actual, type_t *needed)
-{
- if (!actual || !needed)
- return false;
+PUREFUNC bool can_promote(type_t *actual, type_t *needed) {
+ if (!actual || !needed) return false;
// No promotion necessary:
- if (type_eq(actual, needed))
- return true;
+ if (type_eq(actual, needed)) return true;
- if (actual->tag == NumType && needed->tag == IntType)
- return false;
+ if (actual->tag == NumType && needed->tag == IntType) return false;
- if (actual->tag == IntType && (needed->tag == NumType || needed->tag == BigIntType))
- return true;
+ if (actual->tag == IntType && (needed->tag == NumType || needed->tag == BigIntType)) return true;
- if (actual->tag == BigIntType && needed->tag == NumType)
- return true;
+ if (actual->tag == BigIntType && needed->tag == NumType) return true;
if (actual->tag == IntType && needed->tag == IntType) {
precision_cmp_e cmp = compare_precision(actual, needed);
return cmp == NUM_PRECISION_EQUAL || cmp == NUM_PRECISION_LESS;
}
- if (needed->tag == EnumType)
- return (enum_single_value_tag(needed, actual) != NULL);
+ if (needed->tag == EnumType) return (enum_single_value_tag(needed, actual) != NULL);
// Lang to Text:
- if (actual->tag == TextType && needed->tag == TextType && streq(Match(needed, TextType)->lang, "Text"))
- return true;
+ if (actual->tag == TextType && needed->tag == TextType && streq(Match(needed, TextType)->lang, "Text")) return true;
// Text to C String
- if (actual->tag == TextType && !Match(actual, TextType)->lang && needed->tag == CStringType)
- return true;
+ if (actual->tag == TextType && !Match(actual, TextType)->lang && needed->tag == CStringType) return true;
// Automatic dereferencing:
- if (actual->tag == PointerType && can_promote(Match(actual, PointerType)->pointed, needed))
- return true;
+ if (actual->tag == PointerType && can_promote(Match(actual, PointerType)->pointed, needed)) return true;
if (actual->tag == OptionalType) {
- if (needed->tag == BoolType)
- return true;
+ if (needed->tag == BoolType) return true;
// Ambiguous `none` to concrete optional
- if (Match(actual, OptionalType)->type == NULL)
- return (needed->tag == OptionalType);
+ if (Match(actual, OptionalType)->type == NULL) return (needed->tag == OptionalType);
// Optional num -> num
if (needed->tag == NumType && actual->tag == OptionalType && Match(actual, OptionalType)->type->tag == NumType)
@@ -344,7 +300,8 @@ PUREFUNC bool can_promote(type_t *actual, type_t *needed)
}
// Optional promotion:
- if (needed->tag == OptionalType && Match(needed, OptionalType)->type != NULL && can_promote(actual, Match(needed, OptionalType)->type))
+ if (needed->tag == OptionalType && Match(needed, OptionalType)->type != NULL
+ && can_promote(actual, Match(needed, OptionalType)->type))
return true;
if (needed->tag == PointerType && actual->tag == PointerType) {
@@ -361,8 +318,7 @@ PUREFUNC bool can_promote(type_t *actual, type_t *needed)
// Can't use @Foo for a function that wants @Baz
// But you *can* use @Foo for a function that wants @Memory
return false;
- else
- return true;
+ else return true;
}
// Empty literals:
@@ -370,7 +326,8 @@ PUREFUNC bool can_promote(type_t *actual, type_t *needed)
return true; // [] -> [T]
if (actual->tag == SetType && needed->tag == SetType && Match(actual, SetType)->item_type == NULL)
return true; // || -> |T|
- if (actual->tag == TableType && needed->tag == TableType && Match(actual, TableType)->key_type == NULL && Match(actual, TableType)->value_type == NULL)
+ if (actual->tag == TableType && needed->tag == TableType && Match(actual, TableType)->key_type == NULL
+ && Match(actual, TableType)->value_type == NULL)
return true; // {} -> {K=V}
// Cross-promotion between tables with default values and without
@@ -403,10 +360,9 @@ PUREFUNC bool can_promote(type_t *actual, type_t *needed)
type_t *needed_ret = Match(needed, FunctionType)->ret;
if (!needed_ret) needed_ret = Type(VoidType);
- return (
- (type_eq(actual_ret, needed_ret))
- || (actual_ret->tag == PointerType && needed_ret->tag == PointerType
- && can_promote(actual_ret, needed_ret)));
+ return ((type_eq(actual_ret, needed_ret))
+ || (actual_ret->tag == PointerType && needed_ret->tag == PointerType
+ && can_promote(actual_ret, needed_ret)));
}
// Set -> List promotion
@@ -417,30 +373,24 @@ PUREFUNC bool can_promote(type_t *actual, type_t *needed)
return false;
}
-PUREFUNC bool is_int_type(type_t *t)
-{
- return t->tag == IntType || t->tag == BigIntType || t->tag == ByteType;
-}
+PUREFUNC bool is_int_type(type_t *t) { return t->tag == IntType || t->tag == BigIntType || t->tag == ByteType; }
-PUREFUNC bool is_numeric_type(type_t *t)
-{
+PUREFUNC bool is_numeric_type(type_t *t) {
return t->tag == IntType || t->tag == BigIntType || t->tag == NumType || t->tag == ByteType;
}
-PUREFUNC bool is_packed_data(type_t *t)
-{
- if (t->tag == IntType || t->tag == NumType || t->tag == ByteType || t->tag == PointerType || t->tag == BoolType || t->tag == FunctionType) {
+PUREFUNC bool is_packed_data(type_t *t) {
+ if (t->tag == IntType || t->tag == NumType || t->tag == ByteType || t->tag == PointerType || t->tag == BoolType
+ || t->tag == FunctionType) {
return true;
} else if (t->tag == StructType) {
for (arg_t *field = Match(t, StructType)->fields; field; field = field->next) {
- if (!is_packed_data(field->type))
- return false;
+ if (!is_packed_data(field->type)) return false;
}
return true;
} else if (t->tag == EnumType) {
for (tag_t *tag = Match(t, EnumType)->tags; tag; tag = tag->next) {
- if (!is_packed_data(tag->type))
- return false;
+ if (!is_packed_data(tag->type)) return false;
}
return true;
} else {
@@ -448,10 +398,10 @@ PUREFUNC bool is_packed_data(type_t *t)
}
}
-PUREFUNC size_t unpadded_struct_size(type_t *t)
-{
+PUREFUNC size_t unpadded_struct_size(type_t *t) {
if (Match(t, StructType)->opaque)
- compiler_err(NULL, NULL, NULL, "The struct type %s is opaque, so I can't get the size of it", Match(t, StructType)->name);
+ compiler_err(NULL, NULL, NULL, "The struct type %s is opaque, so I can't get the size of it",
+ Match(t, StructType)->name);
arg_t *fields = Match(t, StructType)->fields;
size_t size = 0;
size_t bit_offset = 0;
@@ -469,8 +419,7 @@ PUREFUNC size_t unpadded_struct_size(type_t *t)
bit_offset = 0;
}
size_t align = type_align(field_type);
- if (align > 1 && size % align > 0)
- size += align - (size % align); // Padding
+ if (align > 1 && size % align > 0) size += align - (size % align); // Padding
size += type_size(field_type);
}
}
@@ -481,8 +430,7 @@ PUREFUNC size_t unpadded_struct_size(type_t *t)
return size;
}
-PUREFUNC size_t type_size(type_t *t)
-{
+PUREFUNC size_t type_size(type_t *t) {
if (t == PATH_TYPE) return sizeof(Path_t);
if (t == PATH_TYPE_TYPE) return sizeof(PathType_t);
#ifdef __GNUC__
@@ -490,11 +438,14 @@ PUREFUNC size_t type_size(type_t *t)
#pragma GCC diagnostic ignored "-Wswitch-default"
#endif
switch (t->tag) {
- case UnknownType: case AbortType: case ReturnType: case VoidType: return 0;
+ case UnknownType:
+ case AbortType:
+ case ReturnType:
+ case VoidType: return 0;
case MemoryType: errx(1, "Memory has undefined type size");
case BoolType: return sizeof(bool);
case ByteType: return sizeof(uint8_t);
- case CStringType: return sizeof(char*);
+ case CStringType: return sizeof(char *);
case BigIntType: return sizeof(Int_t);
case IntType: {
switch (Match(t, IntType)->bits) {
@@ -510,9 +461,9 @@ PUREFUNC size_t type_size(type_t *t)
case ListType: return sizeof(List_t);
case SetType: return sizeof(Table_t);
case TableType: return sizeof(Table_t);
- case FunctionType: return sizeof(void*);
- case ClosureType: return sizeof(struct {void *fn, *userdata;});
- case PointerType: return sizeof(void*);
+ case FunctionType: return sizeof(void *);
+ case ClosureType: return sizeof(struct { void *fn, *userdata; });
+ case PointerType: return sizeof(void *);
case OptionalType: {
type_t *nonnull = Match(t, OptionalType)->type;
switch (nonnull->tag) {
@@ -528,8 +479,7 @@ PUREFUNC size_t type_size(type_t *t)
size_t size = unpadded_struct_size(nonnull);
size += sizeof(bool); // is_null flag
size_t align = type_align(nonnull);
- if (align > 0 && (size % align) > 0)
- size = (size + align) - (size % align);
+ if (align > 0 && (size % align) > 0) size = (size + align) - (size % align);
return size;
}
default: return type_size(nonnull);
@@ -537,11 +487,11 @@ PUREFUNC size_t type_size(type_t *t)
}
case StructType: {
if (Match(t, StructType)->opaque)
- compiler_err(NULL, NULL, NULL, "The struct type %s is opaque, so I can't get the size of it", Match(t, StructType)->name);
+ compiler_err(NULL, NULL, NULL, "The struct type %s is opaque, so I can't get the size of it",
+ Match(t, StructType)->name);
size_t size = unpadded_struct_size(t);
size_t align = type_align(t);
- if (size > 0 && align > 0 && (size % align) > 0)
- size = (size + align) - (size % align);
+ if (size > 0 && align > 0 && (size % align) > 0) size = (size + align) - (size % align);
return size;
}
case EnumType: {
@@ -553,7 +503,7 @@ PUREFUNC size_t type_size(type_t *t)
size_t size = type_size(tag->type);
if (size > max_size) max_size = size;
}
- size_t size = sizeof(UnknownType); // generic enum
+ size_t size = sizeof(UnknownType); // generic enum
if (max_align > 1 && size % max_align > 0) // Padding before first union field
size += max_align - (size % max_align);
size += max_size;
@@ -572,8 +522,7 @@ PUREFUNC size_t type_size(type_t *t)
return 0;
}
-PUREFUNC size_t type_align(type_t *t)
-{
+PUREFUNC size_t type_align(type_t *t) {
if (t == PATH_TYPE) return __alignof__(Path_t);
if (t == PATH_TYPE_TYPE) return __alignof__(PathType_t);
#ifdef __GNUC__
@@ -581,11 +530,14 @@ PUREFUNC size_t type_align(type_t *t)
#pragma GCC diagnostic ignored "-Wswitch-default"
#endif
switch (t->tag) {
- case UnknownType: case AbortType: case ReturnType: case VoidType: return 0;
+ case UnknownType:
+ case AbortType:
+ case ReturnType:
+ case VoidType: return 0;
case MemoryType: errx(1, "Memory has undefined type alignment");
case BoolType: return __alignof__(bool);
case ByteType: return __alignof__(uint8_t);
- case CStringType: return __alignof__(char*);
+ case CStringType: return __alignof__(char *);
case BigIntType: return __alignof__(Int_t);
case IntType: {
switch (Match(t, IntType)->bits) {
@@ -601,9 +553,9 @@ PUREFUNC size_t type_align(type_t *t)
case SetType: return __alignof__(Table_t);
case ListType: return __alignof__(List_t);
case TableType: return __alignof__(Table_t);
- case FunctionType: return __alignof__(void*);
- case ClosureType: return __alignof__(struct {void *fn, *userdata;});
- case PointerType: return __alignof__(void*);
+ case FunctionType: return __alignof__(void *);
+ case ClosureType: return __alignof__(struct { void *fn, *userdata; });
+ case PointerType: return __alignof__(void *);
case OptionalType: {
type_t *nonnull = Match(t, OptionalType)->type;
switch (nonnull->tag) {
@@ -624,7 +576,7 @@ PUREFUNC size_t type_align(type_t *t)
compiler_err(NULL, NULL, NULL, "The struct type %s is opaque, so I can't get the alignment of it",
Match(t, StructType)->name);
arg_t *fields = Match(t, StructType)->fields;
- size_t align = t->tag == StructType ? 0 : sizeof(void*);
+ size_t align = t->tag == StructType ? 0 : sizeof(void *);
for (arg_t *field = fields; field; field = field->next) {
size_t field_align = type_align(field->type);
if (field_align > align) align = field_align;
@@ -649,50 +601,39 @@ PUREFUNC size_t type_align(type_t *t)
return 0;
}
-type_t *get_field_type(type_t *t, const char *field_name)
-{
+type_t *get_field_type(type_t *t, const char *field_name) {
t = value_type(t);
switch (t->tag) {
- case PointerType:
- return get_field_type(Match(t, PointerType)->pointed, field_name);
+ case PointerType: return get_field_type(Match(t, PointerType)->pointed, field_name);
case TextType: {
- if (Match(t, TextType)->lang && streq(field_name, "text"))
- return TEXT_TYPE;
+ if (Match(t, TextType)->lang && streq(field_name, "text")) return TEXT_TYPE;
else if (streq(field_name, "length")) return INT_TYPE;
return NULL;
}
case StructType: {
DeclareMatch(struct_t, t, StructType);
for (arg_t *field = struct_t->fields; field; field = field->next) {
- if (streq(field->name, field_name))
- return field->type;
+ if (streq(field->name, field_name)) return field->type;
}
return NULL;
}
case EnumType: {
DeclareMatch(e, t, EnumType);
for (tag_t *tag = e->tags; tag; tag = tag->next) {
- if (streq(field_name, tag->name))
- return Type(BoolType);
+ if (streq(field_name, tag->name)) return Type(BoolType);
}
return NULL;
}
case SetType: {
- if (streq(field_name, "length"))
- return INT_TYPE;
- else if (streq(field_name, "items"))
- return Type(ListType, .item_type=Match(t, SetType)->item_type);
+ if (streq(field_name, "length")) return INT_TYPE;
+ else if (streq(field_name, "items")) return Type(ListType, .item_type = Match(t, SetType)->item_type);
return NULL;
}
case TableType: {
- if (streq(field_name, "length"))
- return INT_TYPE;
- else if (streq(field_name, "keys"))
- return Type(ListType, Match(t, TableType)->key_type);
- else if (streq(field_name, "values"))
- return Type(ListType, Match(t, TableType)->value_type);
- else if (streq(field_name, "fallback"))
- return Type(OptionalType, .type=t);
+ if (streq(field_name, "length")) return INT_TYPE;
+ else if (streq(field_name, "keys")) return Type(ListType, Match(t, TableType)->key_type);
+ else if (streq(field_name, "values")) return Type(ListType, Match(t, TableType)->value_type);
+ else if (streq(field_name, "fallback")) return Type(OptionalType, .type = t);
return NULL;
}
case ListType: {
@@ -703,28 +644,28 @@ type_t *get_field_type(type_t *t, const char *field_name)
}
}
-PUREFUNC type_t *get_iterated_type(type_t *t)
-{
+PUREFUNC type_t *get_iterated_type(type_t *t) {
type_t *iter_value_t = value_type(t);
switch (iter_value_t->tag) {
- case BigIntType: case IntType: return iter_value_t; break;
+ case BigIntType:
+ case IntType: return iter_value_t; break;
case ListType: return Match(iter_value_t, ListType)->item_type; break;
case SetType: return Match(iter_value_t, SetType)->item_type; break;
case TableType: return NULL;
- case FunctionType: case ClosureType: {
+ case FunctionType:
+ case ClosureType: {
// Iterator function
- __typeof(iter_value_t->__data.FunctionType) *fn = iter_value_t->tag == ClosureType ?
- Match(Match(iter_value_t, ClosureType)->fn, FunctionType) : Match(iter_value_t, FunctionType);
- if (fn->args || fn->ret->tag != OptionalType)
- return NULL;
+ __typeof(iter_value_t->__data.FunctionType) *fn =
+ iter_value_t->tag == ClosureType ? Match(Match(iter_value_t, ClosureType)->fn, FunctionType)
+ : Match(iter_value_t, FunctionType);
+ if (fn->args || fn->ret->tag != OptionalType) return NULL;
return Match(fn->ret, OptionalType)->type;
}
default: return NULL;
}
}
-CONSTFUNC bool is_incomplete_type(type_t *t)
-{
+CONSTFUNC bool is_incomplete_type(type_t *t) {
if (t == NULL) return true;
switch (t->tag) {
case ReturnType: return is_incomplete_type(Match(t, ReturnType)->ret);
@@ -738,8 +679,7 @@ CONSTFUNC bool is_incomplete_type(type_t *t)
case FunctionType: {
DeclareMatch(fn, t, FunctionType);
for (arg_t *arg = fn->args; arg; arg = arg->next) {
- if (arg->type == NULL || is_incomplete_type(arg->type))
- return true;
+ if (arg->type == NULL || is_incomplete_type(arg->type)) return true;
}
return fn->ret ? is_incomplete_type(fn->ret) : false;
}
@@ -749,18 +689,14 @@ CONSTFUNC bool is_incomplete_type(type_t *t)
}
}
-CONSTFUNC type_t *most_complete_type(type_t *t1, type_t *t2)
-{
+CONSTFUNC type_t *most_complete_type(type_t *t1, type_t *t2) {
if (!t1) return t2;
if (!t2) return t1;
- if (is_incomplete_type(t1) && is_incomplete_type(t2))
- return NULL;
- else if (!is_incomplete_type(t1) && !is_incomplete_type(t2) && type_eq(t1, t2))
- return t1;
+ if (is_incomplete_type(t1) && is_incomplete_type(t2)) return NULL;
+ else if (!is_incomplete_type(t1) && !is_incomplete_type(t2) && type_eq(t1, t2)) return t1;
- if (t1->tag != t2->tag)
- return NULL;
+ if (t1->tag != t2->tag) return NULL;
switch (t1->tag) {
case ReturnType: {
@@ -792,16 +728,15 @@ CONSTFUNC type_t *most_complete_type(type_t *t1, type_t *t2)
DeclareMatch(fn2, t2, FunctionType);
arg_t *args = NULL;
for (arg_t *arg1 = fn1->args, *arg2 = fn2->args; arg1 || arg2; arg1 = arg1->next, arg2 = arg2->next) {
- if (!arg1 || !arg2)
- return NULL;
+ if (!arg1 || !arg2) return NULL;
type_t *arg_type = most_complete_type(arg1->type, arg2->type);
if (!arg_type) return NULL;
- args = new(arg_t, .type=arg_type, .next=args);
+ args = new (arg_t, .type = arg_type, .next = args);
}
REVERSE_LIST(args);
type_t *ret = most_complete_type(fn1->ret, fn2->ret);
- return ret ? Type(FunctionType, .args=args, .ret=ret) : NULL;
+ return ret ? Type(FunctionType, .args = args, .ret = ret) : NULL;
}
case ClosureType: {
type_t *fn = most_complete_type(Match(t1, ClosureType)->fn, Match(t1, ClosureType)->fn);
@@ -810,35 +745,29 @@ CONSTFUNC type_t *most_complete_type(type_t *t1, type_t *t2)
case PointerType: {
DeclareMatch(ptr1, t1, PointerType);
DeclareMatch(ptr2, t2, PointerType);
- if (ptr1->is_stack != ptr2->is_stack)
- return NULL;
+ if (ptr1->is_stack != ptr2->is_stack) return NULL;
type_t *pointed = most_complete_type(ptr1->pointed, ptr2->pointed);
- return pointed ? Type(PointerType, .is_stack=ptr1->is_stack, .pointed=pointed) : NULL;
+ return pointed ? Type(PointerType, .is_stack = ptr1->is_stack, .pointed = pointed) : NULL;
}
default: {
- if (is_incomplete_type(t1) || is_incomplete_type(t2))
- return NULL;
+ if (is_incomplete_type(t1) || is_incomplete_type(t2)) return NULL;
return type_eq(t1, t2) ? t1 : NULL;
}
}
}
-type_t *_make_function_type(type_t *ret, int n, arg_t args[n])
-{
+type_t *_make_function_type(type_t *ret, int n, arg_t args[n]) {
arg_t *arg_pointers = GC_MALLOC(sizeof(arg_t[n]));
for (int i = 0; i < n; i++) {
arg_pointers[i] = args[i];
- if (i + 1 < n)
- arg_pointers[i].next = &arg_pointers[i+1];
+ if (i + 1 < n) arg_pointers[i].next = &arg_pointers[i + 1];
}
- return Type(FunctionType, .ret=ret, .args=&arg_pointers[0]);
+ return Type(FunctionType, .ret = ret, .args = &arg_pointers[0]);
}
-PUREFUNC bool enum_has_fields(type_t *t)
-{
+PUREFUNC bool enum_has_fields(type_t *t) {
for (tag_t *e_tag = Match(t, EnumType)->tags; e_tag; e_tag = e_tag->next) {
- if (e_tag->type != NULL && Match(e_tag->type, StructType)->fields)
- return true;
+ if (e_tag->type != NULL && Match(e_tag->type, StructType)->fields) return true;
}
return false;
}
diff --git a/src/types.h b/src/types.h
index be16cd5f..2fd1526c 100644
--- a/src/types.h
+++ b/src/types.h
@@ -15,11 +15,13 @@ typedef struct arg_s {
struct arg_s *next;
} arg_t;
-#define ARG_LIST(...) ({\
- arg_t *args[] = {__VA_ARGS__}; \
- for (size_t i = 0; i < sizeof(args)/sizeof(args[0])-1; i++) \
- args[i]->next = args[i+1]; \
- args[0]; })
+#define ARG_LIST(...) \
+ ({ \
+ arg_t *args[] = {__VA_ARGS__}; \
+ for (size_t i = 0; i < sizeof(args) / sizeof(args[0]) - 1; i++) \
+ args[i]->next = args[i + 1]; \
+ args[0]; \
+ })
typedef struct tag_s {
const char *name;
@@ -66,15 +68,18 @@ struct type_s {
struct {
type_t *ret;
} ReturnType;
- struct {} BigIntType;
struct {
- enum { TYPE_IBITS8=8, TYPE_IBITS16=16, TYPE_IBITS32=32, TYPE_IBITS64=64 } bits;
+ } BigIntType;
+ struct {
+ enum { TYPE_IBITS8 = 8, TYPE_IBITS16 = 16, TYPE_IBITS32 = 32, TYPE_IBITS64 = 64 } bits;
} IntType;
- struct {} ByteType;
struct {
- enum { TYPE_NBITS32=32, TYPE_NBITS64=64 } bits;
+ } ByteType;
+ struct {
+ enum { TYPE_NBITS32 = 32, TYPE_NBITS64 = 64 } bits;
} NumType;
- struct {} CStringType;
+ struct {
+ } CStringType;
struct {
const char *lang;
struct env_s *env;
@@ -99,13 +104,13 @@ struct type_s {
} ClosureType;
struct {
type_t *pointed;
- bool is_stack:1;
+ bool is_stack : 1;
} PointerType;
struct {
const char *name;
arg_t *fields;
struct env_s *env;
- bool opaque:1, external:1;
+ bool opaque : 1, external : 1;
} StructType;
struct {
const char *name;
@@ -127,10 +132,11 @@ struct type_s {
} __data;
};
-#define Type(typetag, ...) new(type_t, .tag=typetag, .__data.typetag={__VA_ARGS__})
+#define Type(typetag, ...) new (type_t, .tag = typetag, .__data.typetag = {__VA_ARGS__})
#define INT_TYPE Type(BigIntType)
-#define NUM_TYPE Type(NumType, .bits=TYPE_NBITS64)
-#define NewFunctionType(ret, ...) _make_function_type(ret, sizeof((arg_t[]){__VA_ARGS__})/sizeof(arg_t), (arg_t[]){__VA_ARGS__})
+#define NUM_TYPE Type(NumType, .bits = TYPE_NBITS64)
+#define NewFunctionType(ret, ...) \
+ _make_function_type(ret, sizeof((arg_t[]){__VA_ARGS__}) / sizeof(arg_t), (arg_t[]){__VA_ARGS__})
Text_t type_to_text(type_t *t);
const char *type_to_str(type_t *t);
@@ -139,7 +145,12 @@ PUREFUNC bool type_eq(type_t *a, type_t *b);
PUREFUNC bool type_is_a(type_t *t, type_t *req);
type_t *type_or_type(type_t *a, type_t *b);
type_t *value_type(type_t *a);
-typedef enum {NUM_PRECISION_EQUAL, NUM_PRECISION_LESS, NUM_PRECISION_MORE, NUM_PRECISION_INCOMPARABLE} precision_cmp_e;
+typedef enum {
+ NUM_PRECISION_EQUAL,
+ NUM_PRECISION_LESS,
+ NUM_PRECISION_MORE,
+ NUM_PRECISION_INCOMPARABLE
+} precision_cmp_e;
PUREFUNC precision_cmp_e compare_precision(type_t *a, type_t *b);
PUREFUNC bool has_heap_memory(type_t *t);
PUREFUNC bool has_stack_memory(type_t *t);