mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-11 07:42:18 +00:00
75ec6bf244
This is a nasty commit, sorry, but 99% of the commit is interdependent.
356 lines
11 KiB
R
356 lines
11 KiB
R
#include "Void.h"
|
|
#include "Nil.h"
|
|
#include "Number.h"
|
|
#include "builtins.h"
|
|
#include "defs.h"
|
|
#include "string.h"
|
|
#include "Cons.h"
|
|
#include "Continuation.h"
|
|
#include "BaseContinuation.h"
|
|
#include "Boolean.h"
|
|
#include "Error.h"
|
|
|
|
BOOL num_args (SchemeObject []list, integer num)
|
|
{
|
|
for (; [list isKindOfClass: [Cons class]]; list = [(Cons[]) list cdr]) {
|
|
num--;
|
|
}
|
|
return num == 0;
|
|
}
|
|
|
|
SchemeObject []bi_display (SchemeObject []args, Machine []m)
|
|
{
|
|
if (!num_args(args, 1)) {
|
|
return [Error type: "display"
|
|
message: "expected 1 argument"
|
|
by: m];
|
|
}
|
|
print([[(Cons[]) args car] printForm]);
|
|
return [Void voidConstant];
|
|
}
|
|
|
|
SchemeObject []bi_newline (SchemeObject []args, Machine []m)
|
|
{
|
|
if (!num_args(args, 0)) {
|
|
return [Error type: "newline"
|
|
message: "expected no arguments"
|
|
by: m];
|
|
}
|
|
print("\n");
|
|
return [Void voidConstant];
|
|
}
|
|
|
|
SchemeObject []bi_add (SchemeObject []args, Machine []m)
|
|
{
|
|
local integer sum = 0;
|
|
local SchemeObject []cur;
|
|
|
|
for (cur = args; cur != [Nil nil]; cur = [(Cons[]) cur cdr]) {
|
|
if (![[(Cons[]) cur car] isKindOfClass: [Number class]]) {
|
|
return [Error type: "+"
|
|
message: sprintf("non-number argument: %s\n",
|
|
[[(Cons[]) cur car] printForm])
|
|
by: m];
|
|
}
|
|
sum += [(Number[]) [(Cons[]) cur car] intValue];
|
|
}
|
|
|
|
return [Number newFromInt: sum];
|
|
}
|
|
|
|
SchemeObject []bi_sub (SchemeObject []args, Machine []m)
|
|
{
|
|
local integer diff = 0;
|
|
local SchemeObject []cur;
|
|
|
|
if (args == [Nil nil]) {
|
|
return [Error type: "-"
|
|
message: sprintf("expected at least 1 argument")
|
|
by: m];
|
|
}
|
|
|
|
cur = [(Cons[]) args car];
|
|
|
|
if (![cur isKindOfClass: [Number class]]) {
|
|
return [Error type: "-"
|
|
message: sprintf("non-number argument: %s\n",
|
|
[cur printForm])
|
|
by: m];
|
|
}
|
|
|
|
diff = [(Number[]) cur intValue];
|
|
|
|
if ([(Cons[]) args cdr] == [Nil nil]) {
|
|
return [Number newFromInt: -diff];
|
|
}
|
|
|
|
for (cur = [(Cons[]) args cdr]; cur != [Nil nil]; cur = [(Cons[]) cur cdr]) {
|
|
if (![[(Cons[]) cur car] isKindOfClass: [Number class]]) {
|
|
return [Error type: "-"
|
|
message: sprintf("non-number argument: %s\n",
|
|
[[(Cons[]) cur car] printForm])
|
|
by: m];
|
|
}
|
|
diff -= [(Number[]) [(Cons[]) cur car] intValue];
|
|
}
|
|
|
|
return [Number newFromInt: diff];
|
|
}
|
|
|
|
SchemeObject []bi_mult (SchemeObject []args, Machine []m)
|
|
{
|
|
local integer prod = 1;
|
|
local SchemeObject []cur;
|
|
|
|
for (cur = args; cur != [Nil nil]; cur = [(Cons[]) cur cdr]) {
|
|
if (![[(Cons[]) cur car] isKindOfClass: [Number class]]) {
|
|
return [Error type: "*"
|
|
message: sprintf("non-number argument: %s\n",
|
|
[[(Cons[]) cur car] printForm])
|
|
by: m];
|
|
}
|
|
prod *= [(Number[]) [(Cons[]) cur car] intValue];
|
|
}
|
|
|
|
return [Number newFromInt: prod];
|
|
}
|
|
|
|
SchemeObject []bi_div (SchemeObject []args, Machine []m)
|
|
{
|
|
local integer frac = 0;
|
|
local SchemeObject []cur;
|
|
|
|
if (args == [Nil nil]) {
|
|
return [Error type: "/"
|
|
message: sprintf("expected at least 1 argument")
|
|
by: m];
|
|
}
|
|
|
|
cur = [(Cons[]) args car];
|
|
|
|
if (![cur isKindOfClass: [Number class]]) {
|
|
return [Error type: "/"
|
|
message: sprintf("non-number argument: %s\n",
|
|
[cur printForm])
|
|
by: m];
|
|
}
|
|
|
|
frac = [(Number[]) cur intValue];
|
|
|
|
if ([(Cons[]) args cdr] == [Nil nil]) {
|
|
return [Number newFromInt: 1/frac];
|
|
}
|
|
|
|
for (cur = [(Cons[]) args cdr]; cur != [Nil nil]; cur = [(Cons[]) cur cdr]) {
|
|
if (![[(Cons[]) cur car] isKindOfClass: [Number class]]) {
|
|
return [Error type: "/"
|
|
message: sprintf("non-number argument: %s\n",
|
|
[[(Cons[]) cur car] printForm])
|
|
by: m];
|
|
}
|
|
frac /= [(Number[]) [(Cons[]) cur car] intValue];
|
|
}
|
|
|
|
return [Number newFromInt: frac];
|
|
}
|
|
|
|
SchemeObject []bi_cons (SchemeObject []args, Machine []m)
|
|
{
|
|
if (!num_args(args, 2)) {
|
|
return [Error type: "cons"
|
|
message: "expected 2 arguments"
|
|
by: m];
|
|
}
|
|
[(Cons[]) args cdr: [(Cons[]) [(Cons[]) args cdr] car]];
|
|
return args;
|
|
}
|
|
|
|
SchemeObject []bi_null (SchemeObject []args, Machine []m)
|
|
{
|
|
if (!num_args(args, 1)) {
|
|
return [Error type: "null?"
|
|
message: "expected 1 argument"
|
|
by: m];
|
|
}
|
|
return [(Cons[]) args car] == [Nil nil]
|
|
?
|
|
[Boolean trueConstant] :
|
|
[Boolean falseConstant];
|
|
}
|
|
|
|
SchemeObject []bi_car (SchemeObject []args, Machine []m)
|
|
{
|
|
if (!num_args(args, 1)) {
|
|
return [Error type: "car"
|
|
message: "expected 1 argument"
|
|
by: m];
|
|
}
|
|
if (![[(Cons[]) args car] isKindOfClass: [Cons class]]) {
|
|
return [Error type: "car"
|
|
message: sprintf("expected pair, got: %s",
|
|
[[(Cons[]) args car] printForm])
|
|
by: m];
|
|
}
|
|
|
|
return [(Cons[]) [(Cons[]) args car] car];
|
|
}
|
|
|
|
SchemeObject []bi_cdr (SchemeObject []args, Machine []m)
|
|
{
|
|
if (!num_args(args, 1)) {
|
|
return [Error type: "cdr"
|
|
message: "expected 1 argument"
|
|
by: m];
|
|
}
|
|
if (![[(Cons[]) args car] isKindOfClass: [Cons class]]) {
|
|
return [Error type: "cdr"
|
|
message: sprintf("expected pair, got: %s",
|
|
[[(Cons[]) args car] printForm])
|
|
by: m];
|
|
}
|
|
return [(Cons[]) [(Cons[]) args car] cdr];
|
|
}
|
|
|
|
SchemeObject []bi_apply (SchemeObject []args, Machine []m)
|
|
{
|
|
local SchemeObject []cur, prev;
|
|
if (args == [Nil nil]) {
|
|
return [Error type: "apply"
|
|
message: "expected at least 1 argument"
|
|
by: m];
|
|
} else if (![[(Cons[]) args car] isKindOfClass: [Procedure class]]) {
|
|
return [Error type: "apply"
|
|
message:
|
|
sprintf("expected procedure as 1st argument, got: %s",
|
|
[[(Cons[]) args car] printForm])
|
|
by: m];
|
|
}
|
|
|
|
prev = NIL;
|
|
|
|
for (cur = args; [(Cons[]) cur cdr] != [Nil nil]; cur = [(Cons[]) cur cdr]) {
|
|
prev = cur;
|
|
}
|
|
|
|
if (prev) {
|
|
[(Cons[]) prev cdr: [(Cons[]) cur car]];
|
|
}
|
|
|
|
[m stack: [(Cons[]) args cdr]];
|
|
[(Procedure[]) [(Cons[]) args car] invokeOnMachine: m];
|
|
return NIL;
|
|
}
|
|
|
|
SchemeObject []bi_callcc (SchemeObject []args, Machine []m)
|
|
{
|
|
if (args == [Nil nil]) {
|
|
return [Error type: "call-with-current-continuation"
|
|
message: "expected at least 1 argument"
|
|
by: m];
|
|
} else if (![[(Cons[]) args car] isKindOfClass: [Procedure class]]) {
|
|
return [Error type: "call-with-current-continuation"
|
|
message:
|
|
sprintf("expected procedure as 1st argument, got: %s",
|
|
[[(Cons[]) args car] printForm])
|
|
by: m];
|
|
}
|
|
if ([m continuation]) {
|
|
[m stack: cons([m continuation], [Nil nil])];
|
|
} else {
|
|
[m stack: cons([BaseContinuation baseContinuation],
|
|
[Nil nil])];
|
|
}
|
|
[(Procedure[]) [(Cons[]) args car] invokeOnMachine: m];
|
|
return NIL;
|
|
}
|
|
|
|
SchemeObject []bi_eq (SchemeObject []args, Machine []m)
|
|
{
|
|
if (!num_args(args, 2)) {
|
|
return [Error type: "eq?"
|
|
message: "expected 2 arguments"
|
|
by: m];
|
|
}
|
|
return
|
|
[(Cons[]) args car] == [(Cons[]) [(Cons[]) args cdr] car] ?
|
|
[Boolean trueConstant] :
|
|
[Boolean falseConstant];
|
|
}
|
|
|
|
SchemeObject []bi_numeq (SchemeObject []args, Machine []m)
|
|
{
|
|
local SchemeObject []num1, num2;
|
|
if (!num_args(args, 2)) {
|
|
return [Error type: "="
|
|
message: "expected 2 arguments"
|
|
by: m];
|
|
}
|
|
num1 = [(Cons[]) args car];
|
|
num2 = [(Cons[]) [(Cons[]) args cdr] car];
|
|
if (![num1 isKindOfClass: [Number class]]) {
|
|
return [Error type: "="
|
|
message: sprintf("expected number argument, got: %s",
|
|
[num1 printForm])
|
|
by: m];
|
|
} else if (![num2 isKindOfClass: [Number class]]) {
|
|
return [Error type: "="
|
|
message: sprintf("expected number argument, got: %s",
|
|
[num2 printForm])
|
|
by: m];
|
|
}
|
|
|
|
return
|
|
[(Number[]) num1 intValue] == [(Number[]) num2 intValue] ?
|
|
[Boolean trueConstant] :
|
|
[Boolean falseConstant];
|
|
}
|
|
|
|
SchemeObject []bi_islist (SchemeObject []args, Machine []m)
|
|
{
|
|
if (!num_args(args, 1)) {
|
|
return [Error type: "list?"
|
|
message: "expected 1 argument"
|
|
by: m];
|
|
}
|
|
|
|
return
|
|
isList (args) ?
|
|
[Boolean trueConstant] :
|
|
[Boolean falseConstant];
|
|
}
|
|
|
|
SchemeObject []bi_ispair (SchemeObject []args, Machine []m)
|
|
{
|
|
if (!num_args(args, 1)) {
|
|
return [Error type: "pair?"
|
|
message: "expected 1 argument"
|
|
by: m];
|
|
}
|
|
|
|
return
|
|
[[(Cons[]) args car] isKindOfClass: [Cons class]] ?
|
|
[Boolean trueConstant] :
|
|
[Boolean falseConstant];
|
|
}
|
|
|
|
#define builtin(name, func) [m addGlobal: symbol(#name) value: [Primitive newFromFunc: (func)]]
|
|
|
|
void builtin_addtomachine (Machine []m)
|
|
{
|
|
builtin(display, bi_display);
|
|
builtin(newline, bi_newline);
|
|
builtin(+, bi_add);
|
|
builtin(-, bi_sub);
|
|
builtin(*, bi_mult);
|
|
builtin(/, bi_div);
|
|
builtin(cons, bi_cons);
|
|
builtin(null?, bi_null);
|
|
builtin(car, bi_car);
|
|
builtin(cdr, bi_cdr);
|
|
builtin(apply, bi_apply);
|
|
builtin(call-with-current-continuation, bi_callcc);
|
|
builtin(eq?, bi_eq);
|
|
builtin(=, bi_numeq);
|
|
builtin(list?, bi_islist);
|
|
builtin(pair?, bi_ispair);
|
|
}
|