Skip to content

Commit e09d9ed

Browse files
committed
C interop
1 parent b543402 commit e09d9ed

File tree

4 files changed

+136
-17
lines changed

4 files changed

+136
-17
lines changed

source/backends/linux86.d

Lines changed: 80 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,20 @@ import callisto.parser;
1111
import callisto.compiler;
1212
import callisto.language;
1313

14+
private enum WordType {
15+
Callisto,
16+
Raw,
17+
C
18+
}
19+
1420
private struct Word {
15-
bool raw;
16-
bool inline;
17-
Node[] inlineNodes;
21+
WordType type;
22+
bool inline;
23+
Node[] inlineNodes;
24+
25+
// for C words
26+
Type[] params;
27+
Type* ret;
1828
}
1929

2030
private struct StructEntry {
@@ -312,9 +322,43 @@ class BackendLinux86 : CompilerBackend {
312322
}
313323
}
314324
else {
315-
if (word.raw) {
325+
if (word.type == WordType.Raw) {
316326
output ~= format("call %s\n", node.name);
317327
}
328+
else if (word.type == WordType.C) {
329+
if (word.params.length >= 1) {
330+
output ~= "sub r15, 8\n";
331+
output ~= "mov rdi, [r15]\n";
332+
}
333+
if (word.params.length >= 2) {
334+
output ~= "sub r15, 8\n";
335+
output ~= "mov rsi, [r15]\n";
336+
}
337+
if (word.params.length >= 3) {
338+
output ~= "sub r15, 8\n";
339+
output ~= "mov rdx, [r15]\n";
340+
}
341+
if (word.params.length >= 4) {
342+
output ~= "sub r15, 8\n";
343+
output ~= "mov rcx, [r15]\n";
344+
}
345+
if (word.params.length >= 5) {
346+
output ~= "sub r15, 8\n";
347+
output ~= "mov r8, [r15]\n";
348+
}
349+
if (word.params.length >= 6) {
350+
output ~= "sub r15, 8\n";
351+
output ~= "mov r9, [r15]\n";
352+
}
353+
354+
355+
output ~= format("call %s\n", node.name);
356+
357+
if (word.ret !is null) {
358+
output ~= "mov [r15], rax\n";
359+
output ~= "add r15, 8\n";
360+
}
361+
}
318362
else {
319363
output ~= format("call __func__%s\n", node.name.Sanitise());
320364
}
@@ -368,13 +412,13 @@ class BackendLinux86 : CompilerBackend {
368412
thisFunc = node.name;
369413

370414
if (node.inline) {
371-
words[node.name] = Word(false, true, node.nodes);
415+
words[node.name] = Word(WordType.Callisto, true, node.nodes);
372416
}
373417
else {
374418
assert(!inScope);
375419
inScope = true;
376420

377-
words[node.name] = Word(node.raw, false, []);
421+
words[node.name] = Word(node.raw? WordType.Raw : WordType.Callisto , false, []);
378422

379423
string symbol =
380424
node.raw? node.name : format("__func__%s", node.name.Sanitise());
@@ -785,12 +829,37 @@ class BackendLinux86 : CompilerBackend {
785829

786830
override void CompileExtern(ExternNode node) {
787831
Word word;
788-
word.raw = node.raw;
789-
words[node.func] = word;
790832

791-
if (word.raw) {
833+
final switch (node.externType) {
834+
case ExternType.Callisto: word.type = WordType.Callisto; break;
835+
case ExternType.Raw: word.type = WordType.Raw; break;
836+
case ExternType.C: {
837+
word.type = WordType.C;
838+
839+
foreach (ref param ; node.types) {
840+
if (param !in types) {
841+
Error(node.error, "Unknown type '%s'", param);
842+
}
843+
844+
word.params ~= types[param];
845+
}
846+
847+
if (node.retType != "void") {
848+
if (node.retType !in types) {
849+
Error(node.error, "Unknown type '%s'", node.retType);
850+
}
851+
852+
word.ret = node.retType in types;
853+
}
854+
break;
855+
}
856+
}
857+
858+
if (word.type != WordType.Callisto) {
792859
output ~= format("extern %s\n", node.func);
793860
}
861+
862+
words[node.func] = word;
794863
}
795864

796865
override void CompileCall(WordNode node) {
@@ -805,7 +874,8 @@ class BackendLinux86 : CompilerBackend {
805874
}
806875

807876
auto word = words[node.func];
808-
string symbol = word.raw? node.func : format("__func__%s", node.func.Sanitise());
877+
string symbol = word.type == WordType.Callisto?
878+
format("__func__%s", node.func.Sanitise()) : node.func;
809879

810880
output ~= format("mov rax, %s\n", symbol);
811881
output ~= "mov [r15], rax\n";

source/backends/rm86.d

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -697,7 +697,7 @@ class BackendRM86 : CompilerBackend {
697697

698698
override void CompileExtern(ExternNode node) {
699699
Word word;
700-
word.raw = node.raw;
700+
word.raw = node.externType == ExternType.Raw;
701701
words[node.func] = word;
702702
}
703703

source/backends/uxn.d

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -664,7 +664,7 @@ class BackendUXN : CompilerBackend {
664664

665665
override void CompileExtern(ExternNode node) {
666666
Word word;
667-
word.raw = node.raw;
667+
word.raw = node.externType == ExternType.Raw;
668668
words[node.func] = word;
669669
}
670670

source/parser.d

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -400,16 +400,40 @@ class AliasNode : Node {
400400
override string toString() => format("alias %s %s", to, from);
401401
}
402402

403+
enum ExternType {
404+
Callisto,
405+
Raw,
406+
C
407+
}
408+
403409
class ExternNode : Node {
404-
string func;
405-
bool raw;
410+
string func;
411+
ExternType externType;
412+
413+
// for C extern
414+
string[] types;
415+
string retType;
406416

407417
this(ErrorInfo perror) {
408418
type = NodeType.Extern;
409419
error = perror;
410420
}
411421

412-
override string toString() => format("extern %s%s", raw? "" : "raw ", func);
422+
override string toString() {
423+
final switch (externType) {
424+
case ExternType.Callisto: return format("extern %s", func);
425+
case ExternType.Raw: return format("extern raw %s", func);
426+
case ExternType.C: {
427+
string ret = format("extern C %s %s", retType, func);
428+
429+
foreach (i, ref type ; types) {
430+
ret ~= format(" %s", type);
431+
}
432+
433+
return ret ~ " end";
434+
}
435+
}
436+
}
413437
}
414438

415439
class FuncAddrNode : Node {
@@ -967,13 +991,38 @@ class Parser {
967991
Expect(TokenType.Identifier);
968992

969993
if (tokens[i].contents == "raw") {
970-
ret.raw = true;
994+
ret.externType = ExternType.Raw;
971995

972996
Next();
973997
Expect(TokenType.Identifier);
998+
ret.func = tokens[i].contents;
974999
}
1000+
else if (tokens[i].contents == "C") {
1001+
ret.externType = ExternType.C;
9751002

976-
ret.func = tokens[i].contents;
1003+
Next();
1004+
Expect(TokenType.Identifier);
1005+
ret.retType = tokens[i].contents;
1006+
1007+
Next();
1008+
Expect(TokenType.Identifier);
1009+
ret.func = tokens[i].contents;
1010+
1011+
while (true) {
1012+
Next();
1013+
Expect(TokenType.Identifier);
1014+
1015+
if (tokens[i].contents == "end") {
1016+
break;
1017+
}
1018+
1019+
ret.types ~= tokens[i].contents;
1020+
}
1021+
}
1022+
else {
1023+
ret.externType = ExternType.Callisto;
1024+
ret.func = tokens[i].contents;
1025+
}
9771026

9781027
return ret;
9791028
}

0 commit comments

Comments
 (0)