various: fix string comparison, interpolation and ADD op. for strings
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: Ice1bfb5682ab48a967dc16f1378e23ae6a6a6964
This commit is contained in:
parent
da9be4b014
commit
3441853eef
2 changed files with 50 additions and 16 deletions
|
|
@ -21,10 +21,6 @@ struct IREnvironment {
|
|||
|
||||
explicit IREnvironment(IREnvironment* p = nullptr) : parent(p), with_attrs(nullptr) {}
|
||||
|
||||
IREnvironment* push() {
|
||||
return new IREnvironment(this);
|
||||
}
|
||||
|
||||
void bind(Value* val) {
|
||||
bindings.push_back(val);
|
||||
}
|
||||
|
|
@ -104,7 +100,7 @@ struct Evaluator::Impl {
|
|||
|
||||
thunk->blackholed = true;
|
||||
eval_node(thunk->expr, *v, thunk->env);
|
||||
thunks.erase(it);
|
||||
thunks.erase(v);
|
||||
}
|
||||
|
||||
void eval_node(const std::shared_ptr<Node>& node, Value& v, IREnvironment* env) {
|
||||
|
|
@ -231,6 +227,8 @@ struct Evaluator::Impl {
|
|||
case BinaryOp::ADD:
|
||||
if (left->type() == nInt && right->type() == nInt) {
|
||||
v.mkInt((left->integer() + right->integer()).valueWrapping());
|
||||
} else if (left->type() == nString && right->type() == nString) {
|
||||
v.mkString(std::string(left->c_str()) + std::string(right->c_str()));
|
||||
} else {
|
||||
state.error<EvalError>("type error in addition").debugThrow();
|
||||
}
|
||||
|
|
@ -268,6 +266,8 @@ struct Evaluator::Impl {
|
|||
case BinaryOp::LT:
|
||||
if (left->type() == nInt && right->type() == nInt) {
|
||||
v.mkBool(left->integer() < right->integer());
|
||||
} else if (left->type() == nString && right->type() == nString) {
|
||||
v.mkBool(std::string(left->c_str()) < std::string(right->c_str()));
|
||||
} else {
|
||||
state.error<EvalError>("type error in comparison").debugThrow();
|
||||
}
|
||||
|
|
@ -275,6 +275,8 @@ struct Evaluator::Impl {
|
|||
case BinaryOp::GT:
|
||||
if (left->type() == nInt && right->type() == nInt) {
|
||||
v.mkBool(left->integer() > right->integer());
|
||||
} else if (left->type() == nString && right->type() == nString) {
|
||||
v.mkBool(std::string(left->c_str()) > std::string(right->c_str()));
|
||||
} else {
|
||||
state.error<EvalError>("type error in comparison").debugThrow();
|
||||
}
|
||||
|
|
@ -282,6 +284,8 @@ struct Evaluator::Impl {
|
|||
case BinaryOp::LE:
|
||||
if (left->type() == nInt && right->type() == nInt) {
|
||||
v.mkBool(left->integer() <= right->integer());
|
||||
} else if (left->type() == nString && right->type() == nString) {
|
||||
v.mkBool(std::string(left->c_str()) <= std::string(right->c_str()));
|
||||
} else {
|
||||
state.error<EvalError>("type error in comparison").debugThrow();
|
||||
}
|
||||
|
|
@ -289,16 +293,15 @@ struct Evaluator::Impl {
|
|||
case BinaryOp::GE:
|
||||
if (left->type() == nInt && right->type() == nInt) {
|
||||
v.mkBool(left->integer() >= right->integer());
|
||||
} else if (left->type() == nString && right->type() == nString) {
|
||||
v.mkBool(std::string(left->c_str()) >= std::string(right->c_str()));
|
||||
} else {
|
||||
state.error<EvalError>("type error in comparison").debugThrow();
|
||||
}
|
||||
break;
|
||||
case BinaryOp::CONCAT:
|
||||
if (left->type() == nString && right->type() == nString) {
|
||||
v.mkString(std::string(left->c_str()) + std::string(right->c_str()));
|
||||
} else {
|
||||
state.error<EvalError>("type error in concatenation").debugThrow();
|
||||
}
|
||||
// ++ is list concatenation in Nix; string concat uses ADD (+)
|
||||
state.error<EvalError>("list concatenation not yet implemented").debugThrow();
|
||||
break;
|
||||
default:
|
||||
state.error<EvalError>("unknown binary operator").debugThrow();
|
||||
|
|
@ -410,7 +413,9 @@ struct Evaluator::Impl {
|
|||
auto attr = obj->attrs()->get(sym);
|
||||
|
||||
if (attr) {
|
||||
v = *attr->value;
|
||||
Value* val = attr->value;
|
||||
force(val);
|
||||
v = *val;
|
||||
} else if (n->default_expr) {
|
||||
eval_node(*n->default_expr, v, env);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -27,7 +27,10 @@ static std::string read_file(const std::string& path) {
|
|||
long size = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
std::string content(size, '\0');
|
||||
fread(content.data(), 1, size, f);
|
||||
if (fread(content.data(), 1, size, f) != static_cast<size_t>(size)) {
|
||||
fclose(f);
|
||||
throw std::runtime_error("Failed to read file: " + path);
|
||||
}
|
||||
fclose(f);
|
||||
return content;
|
||||
}
|
||||
|
|
@ -761,7 +764,11 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
expect(Token::RBRACE);
|
||||
if (!consume(Token::RBRACE)) {
|
||||
// Not a lambda pattern, restore
|
||||
pos = saved_pos;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!consume(Token::COLON)) {
|
||||
// Not a lambda, restore
|
||||
|
|
@ -817,6 +824,7 @@ public:
|
|||
// Create lambda
|
||||
auto lambda = LambdaNode(1, let_node);
|
||||
lambda.param_name = arg_name;
|
||||
lambda.strict_pattern = !has_ellipsis;
|
||||
return std::make_shared<Node>(std::move(lambda));
|
||||
}
|
||||
|
||||
|
|
@ -842,13 +850,33 @@ public:
|
|||
i += 2; // Skip ${
|
||||
int depth = 1;
|
||||
size_t expr_start = i;
|
||||
bool in_string = false;
|
||||
char string_quote = 0;
|
||||
|
||||
while (i < raw.size() && depth > 0) {
|
||||
if (raw[i] == '{') depth++;
|
||||
else if (raw[i] == '}') depth--;
|
||||
if (!in_string) {
|
||||
if (raw[i] == '"' || raw[i] == '\'') {
|
||||
in_string = true;
|
||||
string_quote = raw[i];
|
||||
} else if (raw[i] == '{') {
|
||||
depth++;
|
||||
} else if (raw[i] == '}') {
|
||||
depth--;
|
||||
}
|
||||
} else {
|
||||
if (raw[i] == string_quote && (i == 0 || raw[i-1] != '\\')) {
|
||||
in_string = false;
|
||||
} else if (raw[i] == '\\') {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (depth > 0) i++;
|
||||
}
|
||||
|
||||
if (depth > 0) {
|
||||
throw std::runtime_error("unterminated ${ in string interpolation");
|
||||
}
|
||||
|
||||
// Parse the expression
|
||||
std::string expr_str = raw.substr(expr_start, i - expr_start);
|
||||
|
||||
|
|
@ -893,7 +921,8 @@ public:
|
|||
|
||||
auto result = parts[0];
|
||||
for (size_t j = 1; j < parts.size(); j++) {
|
||||
result = std::make_shared<Node>(BinaryOpNode(BinaryOp::CONCAT, result, parts[j]));
|
||||
// Use ADD (+) for string concatenation; CONCAT (++) is Nix list concatenation
|
||||
result = std::make_shared<Node>(BinaryOpNode(BinaryOp::ADD, result, parts[j]));
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue