mirror of
https://github.com/dbalsom/x86_microcode.git
synced 2026-06-09 13:04:17 +03:00
308 lines
11 KiB
C++
308 lines
11 KiB
C++
#include "alfe/main.h"
|
|
|
|
#ifndef INCLUDED_CONFIG_FILE_H
|
|
#define INCLUDED_CONFIG_FILE_H
|
|
|
|
#include "alfe/hash_table.h"
|
|
#include "alfe/space.h"
|
|
#include "alfe/any.h"
|
|
#include "alfe/type.h"
|
|
#include "alfe/set.h"
|
|
#include "alfe/expression.h"
|
|
#include "alfe/function.h"
|
|
#include "alfe/integer_functions.h"
|
|
#include "alfe/string_functions.h"
|
|
#include "alfe/rational_functions.h"
|
|
#include "alfe/concrete_functions.h"
|
|
#include "alfe/array_functions.h"
|
|
#include "alfe/boolean_functions.h"
|
|
#include "alfe/double_functions.h"
|
|
|
|
template<class T> class ConfigFileT;
|
|
typedef ConfigFileT<void> ConfigFile;
|
|
|
|
template<class T, class V> class ConfigOptionT
|
|
{
|
|
public:
|
|
T get() { return _config->template get<T>(_member); }
|
|
private:
|
|
ConfigOptionT(ConfigFile* config, String member)
|
|
: _config(config), _member(member) { }
|
|
ConfigFileT<T>* _config;
|
|
String _member;
|
|
|
|
friend class ConfigFileT<T>;
|
|
};
|
|
|
|
template<class V> using ConfigOption = ConfigOptionT<void, V>;
|
|
|
|
template<class T> class ConfigFileT : public Structure
|
|
{
|
|
public:
|
|
ConfigFileT()
|
|
{
|
|
addType(IntegerType());
|
|
addType(BooleanType());
|
|
addFunco(AddIntegerInteger());
|
|
addFunco(SubtractIntegerInteger());
|
|
addFunco(MultiplyIntegerInteger());
|
|
addFunco(AddStringString());
|
|
addFunco(MultiplyIntegerString());
|
|
addFunco(MultiplyStringInteger());
|
|
addFunco(AddRationalRational());
|
|
addFunco(AddRationalInteger());
|
|
addFunco(AddIntegerRational());
|
|
addFunco(SubtractRationalRational());
|
|
addFunco(SubtractRationalInteger());
|
|
addFunco(SubtractIntegerRational());
|
|
addFunco(MultiplyRationalRational());
|
|
addFunco(MultiplyRationalInteger());
|
|
addFunco(MultiplyIntegerRational());
|
|
addFunco(DivideRationalRational());
|
|
addFunco(DivideRationalInteger());
|
|
addFunco(DivideIntegerRational());
|
|
addFunco(DivideIntegerInteger());
|
|
addFunco(AddConcreteConcrete());
|
|
addFunco(SubtractConcreteConcrete());
|
|
addFunco(MultiplyConcreteConcrete());
|
|
addFunco(MultiplyConcreteRational());
|
|
addFunco(MultiplyRationalConcrete());
|
|
addFunco(DivideConcreteConcrete());
|
|
addFunco(DivideConcreteRational());
|
|
addFunco(DivideRationalConcrete());
|
|
addFunco(ShiftLeftIntegerInteger());
|
|
addFunco(ShiftRightIntegerInteger());
|
|
addFunco(ShiftLeftRationalInteger());
|
|
addFunco(ShiftRightRationalInteger());
|
|
addFunco(ShiftLeftConcreteInteger());
|
|
addFunco(ShiftRightConcreteInteger());
|
|
addFunco(PowerIntegerInteger());
|
|
addFunco(PowerRationalInteger());
|
|
addFunco(NegativeRational());
|
|
addFunco(FloorRational());
|
|
addFunco(IndexArray());
|
|
addFunco(LogicalNotBoolean());
|
|
addFunco(LessThanIntegerInteger());
|
|
addFunco(GreaterThanIntegerInteger());
|
|
addFunco(LessThanOrEqualToIntegerInteger());
|
|
addFunco(GreaterThanOrEqualToIntegerInteger());
|
|
addFunco(NegativeInteger());
|
|
addFunco(AddDoubleDouble());
|
|
addFunco(AddDoubleRational());
|
|
addFunco(AddRationalDouble());
|
|
addFunco(SubtractDoubleDouble());
|
|
addFunco(SubtractDoubleRational());
|
|
addFunco(SubtractRationalDouble());
|
|
addFunco(MultiplyDoubleDouble());
|
|
addFunco(MultiplyDoubleRational());
|
|
addFunco(MultiplyRationalDouble());
|
|
addFunco(DivideDoubleDouble());
|
|
addFunco(DivideDoubleRational());
|
|
addFunco(DivideRationalDouble());
|
|
addFunco(PowerDoubleDouble());
|
|
addFunco(PowerDoubleRational());
|
|
addFunco(PowerRationalDouble());
|
|
addFunco(ShiftLeftDoubleInteger());
|
|
addFunco(ShiftRightDoubleInteger());
|
|
addFunco(NegativeDouble());
|
|
}
|
|
template<class V> ConfigOption<V> addOption(String name)
|
|
{
|
|
addOption(name, typeFromCompileTimeType<V>());
|
|
return ConfigOption<V>(this, name);
|
|
}
|
|
void addOption(String name, Type type)
|
|
{
|
|
addOption(name, Value(type));
|
|
}
|
|
template<class V> void addDefaultOption(String name, Type type,
|
|
const V& defaultValue)
|
|
{
|
|
StructuredType s(type);
|
|
if (s.valid()) {
|
|
addOption(name,
|
|
s.lValueFromRValue(defaultValue, &_structureOwner));
|
|
}
|
|
else
|
|
addOption(name, Value(type, defaultValue));
|
|
}
|
|
template<class V> ConfigOption<V> addDefaultOption(String name,
|
|
const V& defaultValue)
|
|
{
|
|
addDefaultOption(name, typeFromCompileTimeType<V>(), defaultValue);
|
|
return ConfigOption<V>(this, name);
|
|
}
|
|
void addType(Type type, TycoIdentifier identifier = TycoIdentifier())
|
|
{
|
|
_scope.addType(type, identifier);
|
|
}
|
|
private:
|
|
void addOption(String name, Value defaultValue)
|
|
{
|
|
VariableDefinition s(defaultValue.type(), name);
|
|
_scope.addObject(name, s);
|
|
set(name, defaultValue, Span());
|
|
}
|
|
public:
|
|
void addFunco(Funco funco)
|
|
{
|
|
_scope.addFunction(funco.identifier(), funco);
|
|
}
|
|
|
|
void load(File file)
|
|
{
|
|
_file = file;
|
|
loadFromString(file.contents());
|
|
}
|
|
void loadFromString(String contents)
|
|
{
|
|
CharacterSource source(contents, _file);
|
|
Space::parse(&source);
|
|
do {
|
|
CharacterSource s = source;
|
|
if (s.get() == -1)
|
|
break;
|
|
s = source;
|
|
Span span;
|
|
if (Space::parseKeyword(&s, "include", &span)) {
|
|
Expression e = Expression::parse(&s);
|
|
e.resolve(&_scope);
|
|
Value v = e.evaluate(this).convertTo(StringType());
|
|
Space::assertCharacter(&s, ';', &span);
|
|
load(File(v.value<String>(), _file.parent()));
|
|
source = s;
|
|
continue;
|
|
}
|
|
TycoSpecifier tycoSpecifier = TycoSpecifier::parse(&s);
|
|
if (tycoSpecifier.valid()) {
|
|
Type type = _scope.resolveType(tycoSpecifier);
|
|
Identifier objectIdentifier = Identifier::parse(&s);
|
|
if (objectIdentifier.isOperator()) {
|
|
objectIdentifier.span().throwError("Cannot create an "
|
|
"object with operator name");
|
|
}
|
|
String objectName = objectIdentifier.toString();
|
|
if (has(objectIdentifier)) {
|
|
objectIdentifier.span().throwError(objectName +
|
|
" already exists");
|
|
}
|
|
Value value = StructuredType::empty();
|
|
if (Space::parseCharacter(&s, '=', &span)) {
|
|
Expression e = Expression::parse(&s);
|
|
e.resolve(&_scope);
|
|
value = e.evaluate(this);
|
|
}
|
|
Space::assertCharacter(&s, ';', &span);
|
|
source = s;
|
|
value = value.rValue().convertTo(type);
|
|
span = tycoSpecifier.span() + span;
|
|
if (type.member(Identifier("*")) == StringType()) {
|
|
// This special member is how ConfigFile tells created
|
|
// objects their names so that they can responsible for
|
|
// persistence so that this functionality doesn't need to
|
|
// be in ConfigFile.
|
|
// Using an actual identifier here would lead to collisions
|
|
// with real members. ALFE persistence is done by types
|
|
// knowing how to persist themselves.
|
|
// I also don't want to use the empty string, since I might
|
|
// want to use that as the connector name for
|
|
// single-connector components.
|
|
value.value<Structure*>()->set(Identifier("*"),
|
|
objectName, span);
|
|
}
|
|
_scope.addObject(objectIdentifier,
|
|
VariableDefinition(type, objectIdentifier));
|
|
set(objectIdentifier, value, span);
|
|
|
|
continue;
|
|
}
|
|
Identifier identifier = Identifier::parse(&s);
|
|
if (!identifier.valid()) {
|
|
s.location().throwError("Expected an include statement, an "
|
|
"object creation statement or an assignment statement.");
|
|
}
|
|
Expression le = Expression::parseDot(&source);
|
|
le.resolve(&_scope);
|
|
Value left = le.evaluate(this);
|
|
Space::assertCharacter(&source, '=', &span);
|
|
Expression e = Expression::parse(&source);
|
|
if (!e.valid())
|
|
source.location().throwError("Expected expression.");
|
|
Space::assertCharacter(&source, ';', &span);
|
|
e.resolve(&_scope);
|
|
Value loadedExpression = e.evaluate(this);
|
|
LValueType lValueType(left.type());
|
|
if (!lValueType.valid())
|
|
left.span().throwError("LValue required");
|
|
Type type = lValueType.inner();
|
|
LValue p = left.value<LValue>();
|
|
Identifier i = Identifier(OperatorAssignment());
|
|
Value v = loadedExpression.rValue();
|
|
span = left.span() + v.span();
|
|
if (type.member(i).valid()) {
|
|
List<Value> arguments;
|
|
arguments.add(left);
|
|
arguments.add(v);
|
|
auto s = p.rValue().value<Structure*>();
|
|
Value f = s->getValue(i);
|
|
if (f.type() == FuncoType())
|
|
f.value<OverloadedFunctionSet>().evaluate(arguments, span);
|
|
else {
|
|
List<Type> argumentTypes;
|
|
argumentTypes.add(PointerType(type));
|
|
argumentTypes.add(PointerType(v.type()));
|
|
auto func = f.value<Funco>();
|
|
if (!func.argumentsMatch(argumentTypes)) {
|
|
span.throwError("Cannot assign value of type " +
|
|
v.type().toString() + " to object of type " +
|
|
type.toString() + ".");
|
|
}
|
|
func.evaluate(arguments, span);
|
|
}
|
|
}
|
|
else {
|
|
StructuredType s(type);
|
|
if (s.valid())
|
|
s.setLValue(p, v.convertTo(type));
|
|
else
|
|
p.set(v.convertTo(type), span);
|
|
}
|
|
} while (true);
|
|
for (auto i : *this) {
|
|
if (!i.value().valid())
|
|
throw Exception(_file.path() + ": " + i.key().toString() +
|
|
" not defined and no default is available.");
|
|
}
|
|
}
|
|
|
|
File file() const { return _file; }
|
|
|
|
template<class U> U evaluate(String text, const U& def)
|
|
{
|
|
CharacterSource s(text);
|
|
Value c;
|
|
try {
|
|
Expression e = Expression::parse(&s);
|
|
if (!e.valid())
|
|
return def;
|
|
e.resolve(&_scope);
|
|
Value v = e.evaluate(this);
|
|
if (!v.valid())
|
|
return def;
|
|
c = v.convertTo(typeFromCompileTimeType<U>());
|
|
if (!c.valid())
|
|
return def;
|
|
}
|
|
catch (...) {
|
|
return def;
|
|
}
|
|
return c.template value<U>();
|
|
}
|
|
private:
|
|
File _file;
|
|
StructureOwner _structureOwner;
|
|
Scope _scope;
|
|
};
|
|
|
|
#endif // INCLUDED_CONFIG_FILE_H
|