tjysdsg / tan Goto Github PK
View Code? Open in Web Editor NEWA programming language for fun
Home Page: https://tjysdsg.github.io/tan/
License: MIT License
A programming language for fun
Home Page: https://tjysdsg.github.io/tan/
License: MIT License
... and use TypeNode to represent a type during parsing, which will be replaced into an ASTType during analysis phase
tanc --print-ast --print-ir -I/mnt/d/repos/tan src/test/test_src/struct.tan -lruntime -L/mnt/d/repos/tan/runtime -o a.out
[ERROR] at src/test/test_src/struct.tan:27 Cannot perform implicit type conversion
s.pfuck = &f; // pointer
^
0x7faa5edc39de: (__tan_assert_fail()+0xd)
0x7faa5edc4276: (tanlang::report_error(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, tanlang::Token*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)+0x3f7)
0x7faa5ee44004: (tanlang::AnalyzerImpl::report_error(tanlang::ASTBase*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)+0x44)
0x7faa5ee44f1b: (tanlang::AnalyzerImpl::analyze_assignment(tanlang::Assignment*)+0x23f)
0x7faa5ee43d12: (tanlang::AnalyzerImpl::analyze(tanlang::ASTBase*)+0xc2)
0x7faa5ee449ec: (tanlang::AnalyzerImpl::analyze_stmt(tanlang::ASTBase*)+0xa0)
0x7faa5ee43cef: (tanlang::AnalyzerImpl::analyze(tanlang::ASTBase*)+0x9f)
0x7faa5ee45602: (tanlang::AnalyzerImpl::analyze_func_decl(tanlang::ASTBase*)+0x13a)
0x7faa5ee43ec0: (tanlang::AnalyzerImpl::analyze(tanlang::ASTBase*)+0x270)
0x7faa5ee449ec: (tanlang::AnalyzerImpl::analyze_stmt(tanlang::ASTBase*)+0xa0)
0x7faa5ee43cef: (tanlang::AnalyzerImpl::analyze(tanlang::ASTBase*)+0x9f)
0x7faa5ee449ec: (tanlang::AnalyzerImpl::analyze_stmt(tanlang::ASTBase*)+0xa0)
0x7faa5ee43cef: (tanlang::AnalyzerImpl::analyze(tanlang::ASTBase*)+0x9f)
0x7faa5ee4370c: (tanlang::Analyzer::analyze(tanlang::ASTBase*)+0x2a)
0x7faa5edc5b31: (tanlang::Compiler::parse()+0x153)
0x7faa5edb4dab: (compile_files(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, TanCompilation*)+0x47f)
0x7faa5ed980e4: (cli_main(int, char**)+0x1335)
0x7faa5ed94360: (TanCTests::TestBody()+0x1e8)
0x7faa5eea419c: (void testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*)+0x69)
0x7faa5ee9cdad: (void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*)+0x5e)
0x7faa5ee767ec: (testing::Test::Run()+0xf2)
0x7faa5ee771f7: (testing::TestInfo::Run()+0x113)
0x7faa5ee77adc: (testing::TestSuite::Run()+0x12e)
0x7faa5ee84332: (testing::internal::UnitTestImpl::RunAllTests()+0x41c)
0x7faa5eea56b8: (bool testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*)+0x69)
0x7faa5ee9df71: (bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*)+0x5e)
0x7faa5ee82a86: (testing::UnitTest::Run()+0xc4)
0x7faa5ed9407c: (RUN_ALL_TESTS()+0x15)
0x7faa5ed939bf: (main+0xb0)
0x7faa59c270b3: (__libc_start_main+0xf3)
0x7faa5ed936be: (_start+0x2e)
Process finished with exit code 134
Use fuzzing to test the compiler
The compiler main function should only return 0 (successful compilation) or 1 (errors found in source code). By feeding random data to the compiler, we should find and fix bugs that causes it to crash, throw, or return unexpected value.
Code like this doesn't work:
pub fn main() : int {
var s = "string";
s[0] = 'p';
assert(s[0] == 'p');
return 0;
}
The following command should work like tanc
is compiling .cpp
and .tan
files at the same time, and then tanc
should link them with no problems.
tanc main.tan thrid_party_code.cpp -I. -lruntime.so --exe -o a.out
tanc
should recognize .cpp
files first, compile them using clang
, then compile .tan
files, and finally link all object files
/mnt/d/repos/tan/bin/tanc src/test/test_src/intrinsics.tan -Lruntime -lruntime -I. --print-ir
[ERROR] at src/test/test_src/intrinsics.tan:6 Invalid call to compprint, one argument with type 'str' required
@compprint("main function starts");
^
0x7fa6c4f5d5d8: (__tan_assert_fail()+0xd)
0x7fa6c4f5de70: (tanlang::report_error(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, tanlang::Token*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)+0x3f7)
0x7fa6c4ff9830: (tanlang::AnalyzerImpl::report_error(std::shared_ptr<tanlang::ParsableASTNode> const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)+0x4c)
0x7fa6c50194d2: (tanlang::AnalyzerImpl::analyze_intrinsic(std::shared_ptr<tanlang::ParsableASTNode> const&)+0x522)
0x7fa6c4ff8fff: (tanlang::AnalyzerImpl::analyze(std::shared_ptr<tanlang::ParsableASTNode> const&)+0xdf3)
0x7fa6c4ff83f7: (tanlang::AnalyzerImpl::analyze(std::shared_ptr<tanlang::ParsableASTNode> const&)+0x1eb)
0x7fa6c5015c41: (tanlang::AnalyzerImpl::analyze_func_decl(std::shared_ptr<tanlang::ParsableASTNode> const&)+0x265)
0x7fa6c4ff917a: (tanlang::AnalyzerImpl::analyze(std::shared_ptr<tanlang::ParsableASTNode> const&)+0xf6e)
0x7fa6c4ff83f7: (tanlang::AnalyzerImpl::analyze(std::shared_ptr<tanlang::ParsableASTNode> const&)+0x1eb)
0x7fa6c4ff83f7: (tanlang::AnalyzerImpl::analyze(std::shared_ptr<tanlang::ParsableASTNode> const&)+0x1eb)
0x7fa6c4ff7458: (tanlang::Analyzer::analyze(std::shared_ptr<tanlang::ParsableASTNode>)+0x2a)
0x7fa6c4f5f7ed: (tanlang::Compiler::parse()+0x197)
0x7fa6c4f4d6da: (compile_files(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, TanCompilation*)+0x47a)
0x7fa6c4f3006e: (cli_main(int, char**)+0x1335)
0x7fa6c4f438bd: (main+0x24)
0x7fa6bfdd70b3: (__libc_start_main+0xf3)
0x7fa6c4f2e04e: (_start+0x2e)
Process finished with exit code 134
The following code crashes the compiler:
import""runtime/print.tan";
import "runtime/debug.tan";
import "runtime/math.tan";
fn close(a: float, b: float) : bool {
return fabs(a - b) < 0.000001;
}
pub fn main(argc: int, argv: char**) : int {
assert(1 * 2 == 2);
assert(1.5 * 2 == 3.0);
assert(1 + 1 == 2);
assert(1.5 + 1.5 == 3.0);
assert(3.926 * 2 == 3.1415926 * 2);
assert(3.1415926 * 2 == 6.2831852);
assert(0 - 1 == -1);
assert(1 - 1 == 0);
assert(5.2 - 0.3 != 4.9); // expect f32 precision problem
assert(5.2 - 0.4 != 4.8); // expect f32 precision problem
assert(close(5.2 - 0.3, 4.9));
assert(close(5.2 - 0.4, 4.8));
assert(13 / 3 == 4);
assert(1.0 / 2.0 == 0.5);
assert(55 / 11 == 5);
assert(-55 / 11 == -5);
assert(55.0 / 11.0 == 5.0);
assert(-55.0 / 11.0 == -5.0);
assert(55.0 / 11.0 == 5.0);
assert(-55.0 / 11.0 == -5.0);
assert(13 % 2 == 1);
assert(5 % 3 == 2);
assert(7 % 1 == 0);
assert(close(5.3 % 2, 1.3));
assert(13.5 % 2 == 1.5);
print("SUCCESS\n");
return 0;
}
The _bp
of a NUD node is the right binding power, while the one of a LED is the left binding power
CodeFactor found an issue: Check exit code directly with e.g. 'if mycmd;', not indirectly with $?.
It's currently on:
compile-and-test.sh:5
Commit 78fa6f3
/mnt/d/repos/tan/bin/tanc src/test/test_src/pointers.tan -Lruntime -lruntime -I. --print-ir
terminate called after throwing an instance of 'std::out_of_range'
what(): _Map_base::at
Process finished with exit code 134
When compiling the runtime without strack_trace.cpp
, LLVM reported the following error:
/mnt/d/repos/tan/bin/tanc -I. --shared -lunwind -o libruntime.so debug.tan stdlib.tan math.tan --print-ir
; ModuleID = 'debug.tan'
source_filename = "debug.tan"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-linux-gnu"
; Function Attrs: nounwind readnone willreturn
declare void @llvm.donothing() #0
declare extern_weak void @abort()
declare extern_weak void @stack_trace()
define void @assert(i1 %_b) !dbg !4 {
func_entry:
%b = alloca i1
call void @llvm.dbg.declare(metadata i1* %b, metadata !10, metadata !DIExpression()), !dbg !11
store i1 %_b, i1* %b, !dbg !12
call void @llvm.dbg.declare(metadata i1* %b, metadata !13, metadata !DIExpression()), !dbg !14
%0 = load i1, i1* %b, !dbg !15
%1 = icmp eq i1 %0, false, !dbg !15
br i1 %1, label %then, label %fi, !dbg !15
then: ; preds = %func_entry
call void @abort(), !dbg !16
br label %fi, !dbg !16
fi: ; preds = %then, %func_entry
}
; Function Attrs: nounwind readnone speculatable willreturn
declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
attributes #0 = { nounwind readnone willreturn }
attributes #1 = { nounwind readnone speculatable willreturn }
!llvm.module.flags = !{!0, !1}
!llvm.dbg.cu = !{!2}
!0 = !{i32 2, !"Dwarf Version", i32 4}
!1 = !{i32 2, !"Debug Info Version", i32 3}
!2 = distinct !DICompileUnit(language: DW_LANG_C, file: !3, producer: "tan compiler", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug)
!3 = !DIFile(filename: "debug.tan", directory: ".")
!4 = distinct !DISubprogram(name: "assert", linkageName: "assert", scope: !3, file: !3, line: 3, type: !5, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !9)
!5 = !DISubroutineType(types: !6)
!6 = !{!7, !8}
!7 = !DIBasicType(name: "void", encoding: DW_ATE_signed)
!8 = !DIBasicType(name: "bool", size: 1, encoding: DW_ATE_boolean)
!9 = <temporary!> !{}
!10 = !DILocalVariable(name: "b", scope: !4, file: !3, line: 3, type: !8)
!11 = !DILocation(line: 3, column: 15, scope: !4)
!12 = !DILocation(line: 4, column: 16, scope: !4)
!13 = !DILocalVariable(name: "b", arg: 1, scope: !4, file: !3, line: 3, type: !8)
!14 = !DILocation(line: 3, column: 1, scope: !4)
!15 = !DILocation(line: 5, column: 6, scope: !4)
!16 = !DILocation(line: 6, column: 2, scope: !4)
Compiling TAN file: debug.tan.o
Basic Block in function 'assert' does not have terminator!
label %fi
in function assert
LLVM ERROR: Broken function found, compilation aborted!
But compiling the runtime with strack_trace.cpp
was successful.
assert
looks like this:
pub fn assert(b: bool) : void {
if(!b) {
@stack_trace();
abort();
}
}
LLVM added a cleanupret
instruction after the abort
call for some unknown reason (it didn't do this for other functions). Then tanc
recognized that the function had a terminal instruction at the end of the body during IR generation, so no ret void
instruction was inserted.
However, without including stack_trace.cpp
, LLVM somehow removed the cleanupret
instruction during binary code generation, thus reported the error above.
Update:
when compiling with stack-trace.cpp
, the last instruction of the function body becomes opcode 104 (getOpcodeName()
returns "<Invalid operator>")
Currently, pointer dereference is written as:
ptr.*
But it's not consistent with the syntax of this language. More specifically, there's not a clear way to define the token type of *
in this situation. It's definitely not a unary operator, and we probably shouldn't treat .*
as a whole because .
itself is a member access operator.
This syntax was originally inspired by zig. But now I start to think that this is against the syntax consistency goal of this language.
Enum declaration:
enum enum_name {
e1 = 0,
e2,
e3 =255,
}
Allows specifying underlying data type (integers). Default to i32
if not specified.
enum E: i32 {
e1,
e2,
e3,
}
Enums values are specified using dot (.
):
var eee = E.e1;
Get enum name using @enum2str
intrinsic:
var myenum = E.e1;
print(@enum2str(myenum)); // output "e1"
Enums can be implicitly casted to integers (but the some implicit conversion might be invalid depending their underlying type), but integers cannot be implicitly casted to enums.
More details in the example:
enum E: i16 {
e1 = 0,
e2,
e3,
}
var i0: int = E.e1; // good
var i8: = E.e1; // compile error, because i16 cannot be implicitly casted to i8
var e0: E = 0; // compile error
var e1: E = 0 as E; // good
var e2: E = -1 as E; // compile error, because E starts at 0
Enums cannot be implicitly casted from/to any types except integers and bools
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.