irc: add Float and URI literal support
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I40c59d94f650e7b9e68f77598492d7ab6a6a6964
This commit is contained in:
parent
b49044c9a5
commit
38c13de01d
6 changed files with 126 additions and 9 deletions
|
|
@ -6,6 +6,7 @@
|
||||||
#include "nix/expr/eval.hh"
|
#include "nix/expr/eval.hh"
|
||||||
#include "nix/expr/value.hh"
|
#include "nix/expr/value.hh"
|
||||||
#include "nix/util/error.hh"
|
#include "nix/util/error.hh"
|
||||||
|
#include "nix/util/url.hh"
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
@ -108,6 +109,8 @@ struct Evaluator::Impl {
|
||||||
|
|
||||||
if (auto* n = node->get_if<ConstIntNode>()) {
|
if (auto* n = node->get_if<ConstIntNode>()) {
|
||||||
v.mkInt(n->value);
|
v.mkInt(n->value);
|
||||||
|
} else if (auto* n = node->get_if<ConstFloatNode>()) {
|
||||||
|
v.mkFloat(n->value);
|
||||||
} else if (auto* n = node->get_if<ConstStringNode>()) {
|
} else if (auto* n = node->get_if<ConstStringNode>()) {
|
||||||
v.mkString(n->value);
|
v.mkString(n->value);
|
||||||
} else if (auto* n = node->get_if<ConstPathNode>()) {
|
} else if (auto* n = node->get_if<ConstPathNode>()) {
|
||||||
|
|
@ -116,6 +119,11 @@ struct Evaluator::Impl {
|
||||||
v.mkBool(n->value);
|
v.mkBool(n->value);
|
||||||
} else if (auto* n = node->get_if<ConstNullNode>()) { // NOLINT(bugprone-branch-clone)
|
} else if (auto* n = node->get_if<ConstNullNode>()) { // NOLINT(bugprone-branch-clone)
|
||||||
v.mkNull();
|
v.mkNull();
|
||||||
|
} else if (auto* n = node->get_if<ConstURINode>()) {
|
||||||
|
// Parse and validate URI, then create string with URI context
|
||||||
|
auto parsed = parseURL(n->value, true);
|
||||||
|
// Store URI with context - the parsed URL string
|
||||||
|
v.mkString(parsed.to_string(), nix::NixStringContext{}, state.mem);
|
||||||
} else if (auto* n = node->get_if<VarNode>()) {
|
} else if (auto* n = node->get_if<VarNode>()) {
|
||||||
Value* bound = env ? env->lookup(n->index) : nullptr;
|
Value* bound = env ? env->lookup(n->index) : nullptr;
|
||||||
if (!bound && env && n->name.has_value()) {
|
if (!bound && env && n->name.has_value()) {
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,8 @@ struct Token {
|
||||||
STRING_INTERP,
|
STRING_INTERP,
|
||||||
PATH,
|
PATH,
|
||||||
INT,
|
INT,
|
||||||
|
FLOAT,
|
||||||
|
URI,
|
||||||
BOOL,
|
BOOL,
|
||||||
LET,
|
LET,
|
||||||
IN,
|
IN,
|
||||||
|
|
@ -216,14 +218,37 @@ public:
|
||||||
} else if (c == '-') {
|
} else if (c == '-') {
|
||||||
// Check if it's a negative number or minus operator
|
// Check if it's a negative number or minus operator
|
||||||
if (pos + 1 < input.size() && isdigit(input[pos + 1])) {
|
if (pos + 1 < input.size() && isdigit(input[pos + 1])) {
|
||||||
tokenize_int();
|
// Check for negative float
|
||||||
|
if (pos + 2 < input.size() && input[pos + 2] == '.') {
|
||||||
|
tokenize_float();
|
||||||
|
} else {
|
||||||
|
tokenize_int();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
emit(TOKEN(MINUS));
|
emit(TOKEN(MINUS));
|
||||||
}
|
}
|
||||||
} else if (isdigit(c)) {
|
} else if (isdigit(c)) {
|
||||||
tokenize_int();
|
// Check if it's a float (digit followed by '.')
|
||||||
} else if (isalpha(c) || c == '_') {
|
if (pos + 1 < input.size() && input[pos + 1] == '.') {
|
||||||
tokenize_ident();
|
tokenize_float();
|
||||||
|
} else {
|
||||||
|
tokenize_int();
|
||||||
|
}
|
||||||
|
} else if (isalpha(c)) {
|
||||||
|
// Check if it's a URI (contains ://) - look ahead
|
||||||
|
size_t lookahead = pos;
|
||||||
|
while (lookahead < input.size() && (isalnum(input[lookahead]) || input[lookahead] == '_' ||
|
||||||
|
input[lookahead] == '-' || input[lookahead] == '+' ||
|
||||||
|
input[lookahead] == '.'))
|
||||||
|
lookahead++;
|
||||||
|
std::string potential_scheme = input.substr(pos, lookahead - pos);
|
||||||
|
if (lookahead + 2 < input.size() && input[lookahead] == ':' && input[lookahead + 1] == '/' &&
|
||||||
|
input[lookahead + 2] == '/') {
|
||||||
|
// It's a URI, consume the whole thing
|
||||||
|
tokenize_uri();
|
||||||
|
} else {
|
||||||
|
tokenize_ident();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
pos++;
|
pos++;
|
||||||
col++;
|
col++;
|
||||||
|
|
@ -339,12 +364,48 @@ private:
|
||||||
col += num.size();
|
col += num.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tokenize_float() {
|
||||||
|
size_t start = pos;
|
||||||
|
if (input[pos] == '-')
|
||||||
|
pos++;
|
||||||
|
while (pos < input.size() && isdigit(input[pos]))
|
||||||
|
pos++;
|
||||||
|
if (pos < input.size() && input[pos] == '.') {
|
||||||
|
pos++;
|
||||||
|
while (pos < input.size() && isdigit(input[pos]))
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
std::string num = input.substr(start, pos - start);
|
||||||
|
tokens.push_back({Token::FLOAT, num, line, col});
|
||||||
|
col += num.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void tokenize_uri() {
|
||||||
|
size_t start = pos;
|
||||||
|
while (pos < input.size() && !isspace(input[pos]) && input[pos] != ')' && input[pos] != ']' &&
|
||||||
|
input[pos] != ';') {
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
std::string uri = input.substr(start, pos - start);
|
||||||
|
tokens.push_back({Token::URI, uri, line, col});
|
||||||
|
col += uri.size();
|
||||||
|
}
|
||||||
|
|
||||||
void tokenize_ident() {
|
void tokenize_ident() {
|
||||||
size_t start = pos;
|
size_t start = pos;
|
||||||
while (pos < input.size() && (isalnum(input[pos]) || input[pos] == '_' || input[pos] == '-'))
|
while (pos < input.size() && (isalnum(input[pos]) || input[pos] == '_' || input[pos] == '-' ||
|
||||||
|
input[pos] == '+' || input[pos] == '.'))
|
||||||
pos++;
|
pos++;
|
||||||
std::string ident = input.substr(start, pos - start);
|
std::string ident = input.substr(start, pos - start);
|
||||||
|
|
||||||
|
// Check if it's a URI (contains ://)
|
||||||
|
size_t scheme_end = ident.find("://");
|
||||||
|
if (scheme_end != std::string::npos && scheme_end > 0) {
|
||||||
|
tokens.push_back({Token::URI, ident, line, col});
|
||||||
|
col += ident.size();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Token::Type type = Token::IDENT;
|
Token::Type type = Token::IDENT;
|
||||||
if (ident == "let")
|
if (ident == "let")
|
||||||
type = Token::LET;
|
type = Token::LET;
|
||||||
|
|
@ -646,6 +707,16 @@ public:
|
||||||
return std::make_shared<Node>(ConstIntNode(std::stoll(t.value)));
|
return std::make_shared<Node>(ConstIntNode(std::stoll(t.value)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (t.type == Token::FLOAT) {
|
||||||
|
advance();
|
||||||
|
return std::make_shared<Node>(ConstFloatNode(std::stod(t.value)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t.type == Token::URI) {
|
||||||
|
advance();
|
||||||
|
return std::make_shared<Node>(ConstURINode(t.value));
|
||||||
|
}
|
||||||
|
|
||||||
if (t.type == Token::STRING) {
|
if (t.type == Token::STRING) {
|
||||||
advance();
|
advance();
|
||||||
return std::make_shared<Node>(ConstStringNode(t.value));
|
return std::make_shared<Node>(ConstStringNode(t.value));
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,8 @@ struct Serializer::Impl {
|
||||||
NodeType get_node_type(const Node& node) {
|
NodeType get_node_type(const Node& node) {
|
||||||
if (node.holds<ConstIntNode>())
|
if (node.holds<ConstIntNode>())
|
||||||
return NodeType::CONST_INT;
|
return NodeType::CONST_INT;
|
||||||
|
if (node.holds<ConstFloatNode>())
|
||||||
|
return NodeType::CONST_FLOAT;
|
||||||
if (node.holds<ConstStringNode>())
|
if (node.holds<ConstStringNode>())
|
||||||
return NodeType::CONST_STRING;
|
return NodeType::CONST_STRING;
|
||||||
if (node.holds<ConstPathNode>())
|
if (node.holds<ConstPathNode>())
|
||||||
|
|
@ -39,6 +41,8 @@ struct Serializer::Impl {
|
||||||
return NodeType::CONST_BOOL;
|
return NodeType::CONST_BOOL;
|
||||||
if (node.holds<ConstNullNode>())
|
if (node.holds<ConstNullNode>())
|
||||||
return NodeType::CONST_NULL;
|
return NodeType::CONST_NULL;
|
||||||
|
if (node.holds<ConstURINode>())
|
||||||
|
return NodeType::CONST_URI;
|
||||||
if (node.holds<VarNode>())
|
if (node.holds<VarNode>())
|
||||||
return NodeType::VAR;
|
return NodeType::VAR;
|
||||||
if (node.holds<LambdaNode>())
|
if (node.holds<LambdaNode>())
|
||||||
|
|
@ -78,6 +82,11 @@ struct Serializer::Impl {
|
||||||
|
|
||||||
if (auto* n = node.get_if<ConstIntNode>()) {
|
if (auto* n = node.get_if<ConstIntNode>()) {
|
||||||
write_u64(static_cast<uint64_t>(n->value));
|
write_u64(static_cast<uint64_t>(n->value));
|
||||||
|
} else if (auto* n = node.get_if<ConstFloatNode>()) {
|
||||||
|
double val = n->value;
|
||||||
|
uint64_t bits = 0;
|
||||||
|
std::memcpy(&bits, &val, sizeof(bits));
|
||||||
|
write_u64(bits);
|
||||||
} else if (auto* n = node.get_if<ConstStringNode>()) {
|
} else if (auto* n = node.get_if<ConstStringNode>()) {
|
||||||
write_string(n->value);
|
write_string(n->value);
|
||||||
} else if (auto* n = node.get_if<ConstPathNode>()) {
|
} else if (auto* n = node.get_if<ConstPathNode>()) {
|
||||||
|
|
@ -86,6 +95,8 @@ struct Serializer::Impl {
|
||||||
write_u8(n->value ? 1 : 0);
|
write_u8(n->value ? 1 : 0);
|
||||||
} else if (auto* n = node.get_if<ConstNullNode>()) {
|
} else if (auto* n = node.get_if<ConstNullNode>()) {
|
||||||
// No data for null
|
// No data for null
|
||||||
|
} else if (auto* n = node.get_if<ConstURINode>()) {
|
||||||
|
write_string(n->value);
|
||||||
} else if (auto* n = node.get_if<VarNode>()) {
|
} else if (auto* n = node.get_if<VarNode>()) {
|
||||||
write_u32(n->index);
|
write_u32(n->index);
|
||||||
} else if (auto* n = node.get_if<LambdaNode>()) {
|
} else if (auto* n = node.get_if<LambdaNode>()) {
|
||||||
|
|
@ -254,6 +265,12 @@ struct Deserializer::Impl {
|
||||||
int64_t val = static_cast<int64_t>(read_u64());
|
int64_t val = static_cast<int64_t>(read_u64());
|
||||||
return std::make_shared<Node>(ConstIntNode(val, line));
|
return std::make_shared<Node>(ConstIntNode(val, line));
|
||||||
}
|
}
|
||||||
|
case NodeType::CONST_FLOAT: {
|
||||||
|
uint64_t bits = read_u64();
|
||||||
|
double val = 0.0;
|
||||||
|
std::memcpy(&val, &bits, sizeof(val));
|
||||||
|
return std::make_shared<Node>(ConstFloatNode(val, line));
|
||||||
|
}
|
||||||
case NodeType::CONST_STRING: {
|
case NodeType::CONST_STRING: {
|
||||||
std::string val = read_string();
|
std::string val = read_string();
|
||||||
return std::make_shared<Node>(ConstStringNode(val, line));
|
return std::make_shared<Node>(ConstStringNode(val, line));
|
||||||
|
|
@ -268,6 +285,10 @@ struct Deserializer::Impl {
|
||||||
}
|
}
|
||||||
case NodeType::CONST_NULL:
|
case NodeType::CONST_NULL:
|
||||||
return std::make_shared<Node>(ConstNullNode(line));
|
return std::make_shared<Node>(ConstNullNode(line));
|
||||||
|
case NodeType::CONST_URI: {
|
||||||
|
std::string val = read_string();
|
||||||
|
return std::make_shared<Node>(ConstURINode(val, line));
|
||||||
|
}
|
||||||
case NodeType::VAR: {
|
case NodeType::VAR: {
|
||||||
uint32_t index = read_u32();
|
uint32_t index = read_u32();
|
||||||
return std::make_shared<Node>(VarNode(index, "", line));
|
return std::make_shared<Node>(VarNode(index, "", line));
|
||||||
|
|
|
||||||
|
|
@ -19,10 +19,12 @@ constexpr uint32_t IR_VERSION = 2;
|
||||||
|
|
||||||
enum class NodeType : uint8_t {
|
enum class NodeType : uint8_t {
|
||||||
CONST_INT = 0x01,
|
CONST_INT = 0x01,
|
||||||
|
CONST_FLOAT = 0x06,
|
||||||
CONST_STRING = 0x02,
|
CONST_STRING = 0x02,
|
||||||
CONST_PATH = 0x03,
|
CONST_PATH = 0x03,
|
||||||
CONST_BOOL = 0x04,
|
CONST_BOOL = 0x04,
|
||||||
CONST_NULL = 0x05,
|
CONST_NULL = 0x05,
|
||||||
|
CONST_URI = 0x07,
|
||||||
VAR = 0x10,
|
VAR = 0x10,
|
||||||
LAMBDA = 0x20,
|
LAMBDA = 0x20,
|
||||||
APP = 0x21,
|
APP = 0x21,
|
||||||
|
|
@ -77,6 +79,18 @@ struct ConstNullNode {
|
||||||
ConstNullNode(uint32_t l = 0) : line(l) {}
|
ConstNullNode(uint32_t l = 0) : line(l) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ConstFloatNode {
|
||||||
|
double value;
|
||||||
|
uint32_t line = 0;
|
||||||
|
ConstFloatNode(double v = 0.0, uint32_t l = 0) : value(v), line(l) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ConstURINode {
|
||||||
|
std::string value;
|
||||||
|
uint32_t line = 0;
|
||||||
|
ConstURINode(std::string v = "", uint32_t l = 0) : value(std::move(v)), line(l) {}
|
||||||
|
};
|
||||||
|
|
||||||
struct VarNode {
|
struct VarNode {
|
||||||
uint32_t index = 0;
|
uint32_t index = 0;
|
||||||
std::optional<std::string> name;
|
std::optional<std::string> name;
|
||||||
|
|
@ -189,10 +203,11 @@ struct ForceNode {
|
||||||
// Node wraps a variant for type-safe AST
|
// Node wraps a variant for type-safe AST
|
||||||
class Node {
|
class Node {
|
||||||
public:
|
public:
|
||||||
using Variant = std::variant<ConstIntNode, ConstStringNode, ConstPathNode, ConstBoolNode,
|
using Variant = std::variant<ConstIntNode, ConstFloatNode, ConstStringNode, ConstPathNode,
|
||||||
ConstNullNode, VarNode, LambdaNode, AppNode, BinaryOpNode,
|
ConstBoolNode, ConstNullNode, ConstURINode, VarNode, LambdaNode,
|
||||||
UnaryOpNode, AttrsetNode, SelectNode, HasAttrNode, WithNode, IfNode,
|
AppNode, BinaryOpNode, UnaryOpNode, AttrsetNode, SelectNode,
|
||||||
LetNode, LetRecNode, AssertNode, ThunkNode, ForceNode>;
|
HasAttrNode, WithNode, IfNode, LetNode, LetRecNode, AssertNode,
|
||||||
|
ThunkNode, ForceNode>;
|
||||||
|
|
||||||
Variant data;
|
Variant data;
|
||||||
|
|
||||||
|
|
|
||||||
1
tests/float_test.nix
Normal file
1
tests/float_test.nix
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
1.5
|
||||||
1
tests/uri_test.nix
Normal file
1
tests/uri_test.nix
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
https://example.com/path?query=1#frag
|
||||||
Loading…
Add table
Add a link
Reference in a new issue