Apgar ya funciona, no estoy muy contento con indexOf, variableAllowedValues y variableValues

This commit is contained in:
Álvaro González 2026-01-31 19:53:12 +01:00
parent 4569c1c1b0
commit 1a076dff6c
9 changed files with 97 additions and 19 deletions

View file

@ -10,6 +10,16 @@ ENV PUB_CACHE=/cache/pub-cache
ENV GRADLE_USER_HOME=/cache/gradle-cache
RUN mkdir -p $PUB_CACHE $GRADLE_USER_HOME
# To avoid: fatal: detected dubious ownership in repository at '/sdks/flutter'
# Pass this during build: --build-arg USER_ID=$(id -u) --build-arg GROUP_ID=$(id -g)
ARG USER_ID
ARG GROUP_ID
RUN echo "Using UID: $USER_ID and GID: $GROUP_ID"
RUN chown -R $USER_ID:$GROUP_ID $PUB_CACHE $GRADLE_USER_HOME
RUN chown -R $USER_ID:$GROUP_ID /sdks/flutter
USER $USER_ID:$GROUP_ID
# Copy pubspec files and get dependencies
# Commented out to avoid building the app during image creation, this will be handled externally by makefile
# COPY pubspec.yaml pubspec.lock ./

View file

@ -19,12 +19,14 @@ build-linux-debug-container: pub-get-container
build-web-debug-container: pub-get-container
./docker-exec.sh exec flutter build web --debug
run-linux-debug-container: build-linux-debug-container
run-linux-debug-container: pub-get-container
./docker-exec.sh exec flutter run -d linux
run-linux-debug: build-linux-debug-container
run-web-debug-container: pub-get-container
./docker-exec.sh exec flutter run --web-port 8081 -d web-server
run-linux-debug-native: build-linux-debug-container
./build/linux/x64/debug/bundle/d4rt_formulas
run-web-debug-container: build-web-debug-container
./docker-exec.sh exec flutter run -d web-server
#cd build/web && python3 -m http.server 8080
run-web-debug-native: build-web-debug-container
cd build/web && python3 -m http.server 8081

View file

@ -132,9 +132,9 @@ Where:
{"name": "Reflexes", "values": ["No response", "Grimace on aggressive stimulation", "Cry on stimulation"] },
{"name": "SkinColor", "values": ["Blue or pale", "Blue extremities, pink body", "Pink"] }
],
"output": {"name": "Result", "unit": "scalar"},
"output": {"name": "Result", "unit": "string"},
"d4rtCode": """
var total = HeartRate + Breathing + MuscleTone + Reflexes + SkinColor;
var total = indexOf("HeartRate") + indexOf("Breathing") + indexOf("MuscleTone") + indexOf("Reflexes") + indexOf("SkinColor");
late var interpretation;
if( total < 4 ) {
interpretation = 'Critical condition';
@ -154,12 +154,12 @@ Where:
"name": "Compare price per mass",
"description": "Compares two products by their price per mass and returns which is cheaper.",
"input": [
{"name": "price1", "unit": "scalar"},
{"name": "price1", "unit": "currency"},
{"name": "mass1", "unit": "kilogram"},
{"name": "price2", "unit": "scalar"},
{"name": "price2", "unit": "currency"},
{"name": "mass2", "unit": "kilogram"}
],
"output": {"name": "Result", "unit": "scalar"},
"output": {"name": "Result", "unit": "string"},
"d4rtCode": """
var p1 = price1 / mass1;
var p2 = price2 / mass2;

View file

@ -0,0 +1,3 @@
[
{"name": "currency", "symbol": "¤", "isBase": true},
]

View file

@ -1,3 +1,4 @@
[
{"name": "scalar", "symbol": "", "isBase": true},
{"name": "scalar", "symbol": "㊷", "isBase": true},
{"name": "string", "symbol": "🔤", "isBase": true}
]

View file

@ -19,9 +19,12 @@ detect_container(){
fi
}
clean_build_cache(){
$DOCKER builder prune --all --force
}
build_image(){
$DOCKER build -t d4rt-formulas-builder -f Dockerfile .
$DOCKER build --build-arg USER_ID=$(id -u) --build-arg GROUP_ID=$(id -g) --progress=plain -t d4rt-formulas-builder -f Dockerfile .
}
graphic_options(){
@ -45,19 +48,37 @@ graphic_options(){
fi
}
spi_options(){
if [ -e /run/user/$(id -u)/at-spi/bus_0 ]
then
printf " %s " "--env AT_SPI_BUS=/run/user/$(id -u)/at-spi/bus_0"
fi
if [ -e /run/user/$(id -u)/at-spi ]
then
printf " %s " "--volume=/run/user/$(id -u)/at-spi:/run/user/$(id -u)/at-spi"
fi
if [ -e /dev/dri ]
then
printf " %s " "--device /dev/dri"
fi
}
exec_in_container(){
local SPIOPTIONS="--env AT_SPI_BUS=/run/user/$(id -u)/at-spi/bus_0 --volume=/run/user/$(id -u)/at-spi:/run/user/$(id -u)/at-spi --device=/dev/dri"
SPIOPTIONS=
SPIOPTIONS=$(spi_options)
local GRAPHICOPTIONS=$(graphic_options)
local BUILDCACHE=./.build-container-cache
mkdir -p $BUILDCACHE
$DOCKER run \
-it \
--userns=keep-id \
--user $(id -u):$(id -g) \
--init \
--rm \
$GRAPHICOPTIONS \
$SPIOPTIONS \
-p ${WEBPORT:-8081}:8081 \
-v $BUILDCACHE:/cache:z \
-v .:/app:z \
-e FLUTTER_FLAVOR=prod \
@ -73,12 +94,18 @@ main(){
return $?
fi
if [ "$1" = "cleancache" ]; then
clean_build_cache
return $?
fi
if [ "$1" = "exec" ]; then
exec_in_container ${@:2}
return $?
fi
echo "Usage: $0 {build|exec <command>}"
echo "Usage: $0 {build|cleancache|exec <command>}"
return 1
}

View file

@ -94,7 +94,6 @@ class _FormulaScreenState extends State<FormulaScreen> {
void _evaluateFormula() {
print( "EVALUATE FORMULA");
if (!_formKey.currentState!.validate()) return;
try {
final inputValues = <String, dynamic>{};
@ -145,7 +144,7 @@ class _FormulaScreenState extends State<FormulaScreen> {
// Convert output to selected unit if needed
String? unit = widget.formula.output.unit;
if (unit != null && unit is Number) {
if (unit != null && result is Number) {
final converted = widget.corpus.convert(result, unit, _selectedOutputUnit!);
if (converted is num) {
_result = converted.toStringAsFixed(2);
@ -274,6 +273,7 @@ class _FormulaScreenState extends State<FormulaScreen> {
onUnitChanged: (unit) {
_selectedOutputUnit = unit;
_evaluateFormula();
print( "En output unit changed to $unit: $_result");
setState(() {
});
},

View file

@ -20,6 +20,7 @@ Future<Corpus> createDefaultCorpus() async{
final unitResources = [
"assets/units/angle.d4rt.units",
"assets/units/area.d4rt.units",
"assets/units/currency.d4rt.units",
"assets/units/distance.d4rt.units",
"assets/units/energy.d4rt.units",
"assets/units/force.d4rt.units",
@ -32,6 +33,7 @@ Future<Corpus> createDefaultCorpus() async{
];
for (final unitRes in unitResources) {
print( "Loading units from $unitRes");
final literal = await loadResourceAsString(unitRes);
final units = UnitSpec.fromArrayStringLiteral(literal);
corpus.loadUnits(units);

View file

@ -104,8 +104,9 @@ class FormulaEvaluator {
final result = _interpreter.execute(source: completeSource);
return result;
}
catch (e) {
catch (e, stack) {
print( "Error evaluating formula source:\n$completeSource" );
print( stack );
throw FormulaEvaluationException(
'Error evaluating formula "${formula.name}": $e',
e,
@ -168,6 +169,29 @@ class FormulaEvaluator {
""");
}
}
buffer.writeln("""
final variableValues = <String, dynamic>{
""");
for (final entry in inputValues.entries) {
final varName = entry.key;
final value = entry.value;
if (value is String) {
final escapedValue = value.replaceAll('"', '\\"');
buffer.writeln("""
"$varName": "$escapedValue",
""");
} else {
buffer.writeln("""
"$varName": "$value",
""");
}
}
buffer.writeln("""
};
""");
// Build a Map<String, List<String>> named `variableValues` that exposes allowed values
// for each VariableSpec (inputs and output) to the interpreted code. Values are
// converted to strings and quoted in the produced d4rt source.
@ -187,13 +211,22 @@ class FormulaEvaluator {
}
// Write the variableValues map into the generated source without escaping names/values
buffer.writeln("final variableValues = {");
buffer.writeln("final variableAllowedValues = {");
variableValuesMap.forEach((name, list) {
final listLiteral = list.map((s) => '"' + s + '"').join(', ');
buffer.writeln(' "' + name + '": [' + listLiteral + '],');
});
buffer.writeln('};');
// Some functions to deal with string values
buffer.writeln("""
int indexOf(String inputName) {
String value = variableValues[inputName];
String allowedValues = variableAllowedValues[inputName];
return allowedValues.indexOf(value);
}
""");
buffer.writeln("""
late var ${formula.output.name};
${formula.d4rtCode}