feat: add JSON parsing and manipulation support

Add comprehensive JSON support via the Json module:
- Parse JSON strings with Json.parse() returning Result<Json, String>
- Stringify with Json.stringify() and Json.prettyPrint()
- Extract values with Json.get(), getIndex(), asString(), asInt(), etc.
- Build JSON with constructors: Json.null(), bool(), int(), string(), array(), object()
- Query with Json.isNull() and Json.keys()

Includes example at examples/json.lux demonstrating building, parsing,
and extracting JSON data with file I/O integration.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-13 16:22:35 -05:00
parent b0f6756411
commit ef9746c2fe
3 changed files with 580 additions and 0 deletions

View File

@@ -732,6 +732,37 @@ impl TypeEnv {
]),
);
// Add Json type (represents JSON values)
env.types.insert(
"Json".to_string(),
TypeDef::Enum(vec![
VariantDef {
name: "JsonNull".to_string(),
fields: VariantFieldsDef::Unit,
},
VariantDef {
name: "JsonBool".to_string(),
fields: VariantFieldsDef::Tuple(vec![Type::Bool]),
},
VariantDef {
name: "JsonNumber".to_string(),
fields: VariantFieldsDef::Tuple(vec![Type::Float]),
},
VariantDef {
name: "JsonString".to_string(),
fields: VariantFieldsDef::Tuple(vec![Type::String]),
},
VariantDef {
name: "JsonArray".to_string(),
fields: VariantFieldsDef::Tuple(vec![Type::List(Box::new(Type::Named("Json".to_string())))]),
},
VariantDef {
name: "JsonObject".to_string(),
fields: VariantFieldsDef::Tuple(vec![Type::List(Box::new(Type::Tuple(vec![Type::String, Type::Named("Json".to_string())])))]),
},
]),
);
// Add Console effect
env.effects.insert(
"Console".to_string(),
@@ -1191,6 +1222,122 @@ impl TypeEnv {
]);
env.bind("String", TypeScheme::mono(string_module_type));
// Json module
let json_type = Type::Named("Json".to_string());
let json_module_type = Type::Record(vec![
(
"parse".to_string(),
Type::function(
vec![Type::String],
Type::App {
constructor: Box::new(Type::Named("Result".to_string())),
args: vec![json_type.clone(), Type::String],
},
),
),
(
"stringify".to_string(),
Type::function(vec![json_type.clone()], Type::String),
),
(
"prettyPrint".to_string(),
Type::function(vec![json_type.clone()], Type::String),
),
(
"get".to_string(),
Type::function(
vec![json_type.clone(), Type::String],
Type::Option(Box::new(json_type.clone())),
),
),
(
"getIndex".to_string(),
Type::function(
vec![json_type.clone(), Type::Int],
Type::Option(Box::new(json_type.clone())),
),
),
(
"asString".to_string(),
Type::function(
vec![json_type.clone()],
Type::Option(Box::new(Type::String)),
),
),
(
"asNumber".to_string(),
Type::function(
vec![json_type.clone()],
Type::Option(Box::new(Type::Float)),
),
),
(
"asInt".to_string(),
Type::function(
vec![json_type.clone()],
Type::Option(Box::new(Type::Int)),
),
),
(
"asBool".to_string(),
Type::function(
vec![json_type.clone()],
Type::Option(Box::new(Type::Bool)),
),
),
(
"asArray".to_string(),
Type::function(
vec![json_type.clone()],
Type::Option(Box::new(Type::List(Box::new(json_type.clone())))),
),
),
(
"isNull".to_string(),
Type::function(vec![json_type.clone()], Type::Bool),
),
(
"keys".to_string(),
Type::function(
vec![json_type.clone()],
Type::List(Box::new(Type::String)),
),
),
// Constructors for building JSON
(
"null".to_string(),
Type::function(vec![], json_type.clone()),
),
(
"bool".to_string(),
Type::function(vec![Type::Bool], json_type.clone()),
),
(
"number".to_string(),
Type::function(vec![Type::Float], json_type.clone()),
),
(
"int".to_string(),
Type::function(vec![Type::Int], json_type.clone()),
),
(
"string".to_string(),
Type::function(vec![Type::String], json_type.clone()),
),
(
"array".to_string(),
Type::function(vec![Type::List(Box::new(json_type.clone()))], json_type.clone()),
),
(
"object".to_string(),
Type::function(
vec![Type::List(Box::new(Type::Tuple(vec![Type::String, json_type.clone()])))],
json_type.clone(),
),
),
]);
env.bind("Json", TypeScheme::mono(json_module_type));
// Option module
let option_module_type = Type::Record(vec![
(