Add string parsing and a print builtin (#721)

It was in my mind to add String in order to support libraries in `package`.  `print` is added in order to have a String go to stdout. I've tried to do `print` in a way that won't be too hard to add other printable types, but it's probably also somewhat optional here -- that is, if desired, I could remove it. But it was a lot easier to doublecheck `\n` behavior with it, and I suspect it'll be helpful in other tests if it supports more value types.

On the side, this also fixes dereferencing in Pattern/Expression Print() calls, which I was noticing printing pointers instead of values. This may be another argument for moving away from passing pointers, since this seems to be a difficult-to-catch error.

Co-authored-by: Geoff Romer <gromer@google.com>
This commit is contained in:
Jon Meow
2021-08-11 13:14:05 -07:00
committed by GitHub
co-authored by Geoff Romer
parent ecb5a611e5
commit 250ce4ab00
36 changed files with 549 additions and 33 deletions
@@ -60,6 +60,15 @@ auto CurrentEnv(State* state) -> Env {
return frame->scopes.Top()->values;
}
// Returns the given name from the environment, printing an error if not found.
static auto GetFromEnv(int line_num, const std::string& name) -> Address {
std::optional<Address> pointer = CurrentEnv(state).Get(name);
if (!pointer) {
FATAL_RUNTIME_ERROR(line_num) << "could not find `" << name << "`";
}
return *pointer;
}
void PrintState(llvm::raw_ostream& out) {
out << "{\nstack: ";
PrintStack(state->stack, out);
@@ -411,14 +420,9 @@ void StepLvalue() {
case Expression::Kind::IdentifierExpression: {
// { {x :: C, E, F} :: S, H}
// -> { {E(x) :: C, E, F} :: S, H}
std::optional<Address> pointer =
CurrentEnv(state).Get(cast<IdentifierExpression>(*exp).Name());
if (!pointer) {
FATAL_RUNTIME_ERROR(exp->LineNumber())
<< "could not find `" << cast<IdentifierExpression>(*exp).Name()
<< "`";
}
const Value* v = global_arena->New<PointerValue>(*pointer);
Address pointer = GetFromEnv(exp->LineNumber(),
cast<IdentifierExpression>(*exp).Name());
const Value* v = global_arena->New<PointerValue>(pointer);
frame->todo.Pop();
frame->todo.Push(global_arena->New<ValAction>(v));
break;
@@ -496,10 +500,12 @@ void StepLvalue() {
case Expression::Kind::BoolTypeLiteral:
case Expression::Kind::TypeTypeLiteral:
case Expression::Kind::FunctionTypeLiteral:
case Expression::Kind::ContinuationTypeLiteral: {
case Expression::Kind::ContinuationTypeLiteral:
case Expression::Kind::StringLiteral:
case Expression::Kind::StringTypeLiteral:
case Expression::Kind::IntrinsicExpression:
FATAL_RUNTIME_ERROR_NO_LINE()
<< "Can't treat expression as lvalue: " << *exp;
}
}
}
@@ -597,12 +603,8 @@ void StepExp() {
CHECK(act->Pos() == 0);
const auto& ident = cast<IdentifierExpression>(*exp);
// { {x :: C, E, F} :: S, H} -> { {H(E(x)) :: C, E, F} :: S, H}
std::optional<Address> pointer = CurrentEnv(state).Get(ident.Name());
if (!pointer) {
FATAL_RUNTIME_ERROR(exp->LineNumber())
<< "could not find `" << ident.Name() << "`";
}
const Value* pointee = state->heap.Read(*pointer, exp->LineNumber());
Address pointer = GetFromEnv(exp->LineNumber(), ident.Name());
const Value* pointee = state->heap.Read(pointer, exp->LineNumber());
frame->todo.Pop(1);
frame->todo.Push(global_arena->New<ValAction>(pointee));
break;
@@ -660,6 +662,22 @@ void StepExp() {
FATAL() << "in handle_value with Call pos " << act->Pos();
}
break;
case Expression::Kind::IntrinsicExpression:
CHECK(act->Pos() == 0);
// { {n :: C, E, F} :: S, H} -> { {n' :: C, E, F} :: S, H}
frame->todo.Pop(1);
switch (cast<IntrinsicExpression>(*exp).Intrinsic()) {
case IntrinsicExpression::IntrinsicKind::Print:
Address pointer = GetFromEnv(exp->LineNumber(), "format_str");
const Value* pointee = state->heap.Read(pointer, exp->LineNumber());
CHECK(pointee->Tag() == Value::Kind::StringValue);
// TODO: This could eventually use something like llvm::formatv.
llvm::outs() << cast<StringValue>(*pointee).Val();
frame->todo.Push(global_arena->New<ValAction>(&TupleValue::Empty()));
break;
}
break;
case Expression::Kind::IntTypeLiteral: {
CHECK(act->Pos() == 0);
const Value* v = global_arena->New<IntType>();
@@ -710,6 +728,20 @@ void StepExp() {
frame->todo.Push(global_arena->New<ValAction>(v));
break;
}
case Expression::Kind::StringLiteral:
CHECK(act->Pos() == 0);
// { {n :: C, E, F} :: S, H} -> { {n' :: C, E, F} :: S, H}
frame->todo.Pop(1);
frame->todo.Push(global_arena->New<ValAction>(
global_arena->New<StringValue>(cast<StringLiteral>(*exp).Val())));
break;
case Expression::Kind::StringTypeLiteral: {
CHECK(act->Pos() == 0);
const Value* v = global_arena->New<StringType>();
frame->todo.Pop(1);
frame->todo.Push(global_arena->New<ValAction>(v));
break;
}
} // switch (exp->Tag)
}