CaRMtl/rene/zirkel/construction/Interpreter.java
2018-09-04 22:51:42 -04:00

811 lines
27 KiB
Java

/*
Copyright 2006 Rene Grothmann, modified by Eric Hakenholz
This file is part of C.a.R. software.
C.a.R. is a free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 3 of the License.
C.a.R. is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package rene.zirkel.construction;
import java.util.Vector;
import rene.gui.Global;
import rene.zirkel.ZirkelCanvas;
import rene.zirkel.ZirkelFrame;
import rene.zirkel.constructors.AngleConstructor;
import rene.zirkel.constructors.AreaConstructor;
import rene.zirkel.constructors.CircleConstructor;
import rene.zirkel.constructors.ExpressionConstructor;
import rene.zirkel.constructors.FunctionConstructor;
import rene.zirkel.constructors.IntersectionConstructor;
import rene.zirkel.constructors.LineConstructor;
import rene.zirkel.constructors.MidpointConstructor;
import rene.zirkel.constructors.ObjectConstructor;
import rene.zirkel.constructors.ParallelConstructor;
import rene.zirkel.constructors.PlumbConstructor;
import rene.zirkel.constructors.PointConstructor;
import rene.zirkel.constructors.QuadricConstructor;
import rene.zirkel.constructors.RayConstructor;
import rene.zirkel.constructors.SegmentConstructor;
import rene.zirkel.macro.Macro;
import rene.zirkel.macro.MacroRunner;
import rene.zirkel.objects.AngleObject;
import rene.zirkel.objects.CircleObject;
import rene.zirkel.objects.ConstructionObject;
import rene.zirkel.objects.ExpressionObject;
import rene.zirkel.objects.FixedAngleObject;
import rene.zirkel.objects.FixedCircleObject;
import rene.zirkel.objects.IntersectionObject;
import rene.zirkel.objects.LineObject;
import rene.zirkel.objects.PlumbObject;
import rene.zirkel.objects.PointObject;
import rene.zirkel.objects.PrimitiveCircleObject;
import rene.zirkel.objects.SegmentObject;
import rene.zirkel.objects.TwoPointLineObject;
public class Interpreter {
Construction C;
public Interpreter(final Construction c) {
C = c;
}
/**
* This is to interpret a single line of input in descriptive mode or a
* single line read from a construction description in a file.
*/
public void interpret(final ZirkelCanvas zc, String s, final String comment)
throws ConstructionException {
boolean Parameter = false, Target = false, Prompt = false;
final Vector V = C.V;
final int VN = V.size(); // note the current construction size
int k;
// Look for special start tags:
if ((k = startTest("parameter", s)) >= 0)
// Parameter objects are set at the end of the function.
{
Parameter = true;
s = s.substring(k).trim();
} else if (s.toLowerCase().equals(Global.name("showall"))
|| s.toLowerCase().equals("showall"))
// This will show all objects even, if there are targets
{
C.ShowAll = true;
return;
} else if (s.toLowerCase().equals(Global.name("invisible"))
|| s.toLowerCase().equals("invisible"))
// This will superhide all objects
{
C.SuperHide = true;
return;
} else if ((k = startTest("target", s)) >= 0)
// Target objects are either set immediate (name only) or
// at the end of the function.
{
Target = true;
s = s.substring(k).trim();
final ConstructionObject o = C.find(s);
// see, if the target ist constructable from the
// parameters, which are already marked cosntructable.
C.determineConstructables();
if (o != null && o.isFlag()) {
o.setTarget(true);
C.addTarget(o);
return;
} else {
Target = true;
}
} else if ((k = startTest("prompt", s)) >= 0) {
Prompt = true;
s = s.substring(k).trim();
if (C.find(s) != null) {
C.PromptFor.addElement(s);
return;
}
}
// Interpret s. First decompose into function and parameters:
String name = "", function = "";
final String params[] = new String[16];
int NParams = 0, n;
if ((n = s.indexOf('=')) >= 0) {
name = s.substring(0, n).trim();
s = s.substring(n + 1).trim();
}
int bracketn = 0;
if (s.startsWith("\"")) {
bracketn = s.indexOf("\"", 1);
}
if (bracketn < 0) {
throw new ConstructionException("exception.brackets");
}
if ((n = s.indexOf('(', bracketn)) >= 0) {
function = s.substring(0, n).trim();
if (function.startsWith("\"") && function.endsWith("\"")
&& function.length() > 1) {
function = function.substring(1, function.length() - 1);
}
s = s.substring(n + 1).trim();
if (!s.endsWith(")")) {
throw new ConstructionException("exception.brackets");
}
final char a[] = s.substring(0, s.length() - 1).toCharArray();
int ia = 0;
int BCount = 0;
while (ia < a.length && NParams < params.length) {
final int ia0 = ia;
while (ia < a.length && (BCount > 0 || a[ia] != ',')) {
if (a[ia] == '\"') {
ia++;
while (ia < a.length && a[ia] != '\"') {
ia++;
}
if (ia >= a.length) {
throw new ConstructionException(Global.name("exception.quotes"));
}
ia++;
} else if (a[ia] == '(') {
BCount++;
ia++;
} else if (a[ia] == ')') {
if (BCount > 0) {
BCount--;
}
else {
throw new ConstructionException(Global.name("exception.brackets"));
}
ia++;
} else {
ia++;
}
}
params[NParams++] = new String(a, ia0, ia - ia0).trim();
ia++;
}
} else {
function = s;
}
final String f = function;
// Interpret special functions:
if (NParams == 3 && ptest(f, "window"))
// window size
{
try {
final double x = new Double(params[0]).doubleValue();
final double y = new Double(params[1]).doubleValue();
final double w = new Double(params[2]).doubleValue();
C.setXYW(x, y, w);
zc.recompute();
} catch (final Exception e) {
throw new ConstructionException(Global.name("exception.value"));
}
return;
}
if ((NParams == 1 || NParams == 2) && ptest(f, "color"))
// color for object or default color
{
int i = 0;
for (i = 0; i < ZirkelFrame.ColorStrings.length; i++) {
if (test(params[0], "colors", ZirkelFrame.ColorStrings[i])) {
break;
}
}
if (i < ZirkelFrame.ColorStrings.length) {
if (NParams == 2) {
final ConstructionObject o = C.find(params[1]);
if (o == null) {
throw new ConstructionException(Global.name("exception.notfound"));
}
o.setColor(i);
} else {
C.DefaultColor = i;
}
} else {
throw new ConstructionException(Global.name("exception.color"));
}
return;
}
if ((NParams == 1 || NParams == 2) && ptest(f, "thickness"))
// thickness for objects or default thickness
{
int i;
for (i = 0; i < ZirkelFrame.ColorTypes.length; i++) {
if (test(params[0], "color.type", ZirkelFrame.ColorTypes[i])) {
break;
}
}
if (i < ZirkelFrame.ColorTypes.length) {
if (NParams == 2) {
final ConstructionObject o = C.find(params[1]);
if (o == null) {
throw new ConstructionException(Global.name("exception.notfound"));
}
o.setColorType(i);
} else {
C.DefaultColorType = i;
}
} else {
throw new ConstructionException(Global.name("exception.colortype"));
}
return;
}
if ((NParams == 1 || NParams == 2) && ptest(f, "type"))
// point type for point or default point type
{
int i;
for (i = 0; i < ZirkelFrame.PointTypes.length; i++) {
if (test(params[0], "point.type", ZirkelFrame.PointTypes[i])) {
break;
}
}
if (i < ZirkelFrame.PointTypes.length) {
if (NParams == 2) {
final ConstructionObject o = C.find(params[1]);
if (o == null || !(o instanceof PointObject)) {
throw new ConstructionException(Global.name("exception.notfound"));
}
((PointObject) o).setType(i);
} else {
C.DefaultType = i;
}
} else {
throw new ConstructionException(Global.name("exception.type"));
}
return;
}
if ((NParams == 1 || NParams == 2) && ptest(f, "partial"))
// partail view for circle or line or default partial view
{
if (NParams == 1 && !truecheck(params[0])) {
final ConstructionObject o = C.find(params[0]);
if (o == null) {
throw new ConstructionException(Global.name("exception.notfound"));
}
if (o instanceof PrimitiveCircleObject) {
((PrimitiveCircleObject) o).setPartial(true);
}
if (o instanceof LineObject) {
((LineObject) o).setPartial(true);
}
return;
}
final boolean partial = truetest(params[0]);
if (NParams == 2) {
final ConstructionObject o = C.find(params[1]);
if (o == null) {
throw new ConstructionException(Global.name("exception.notfound"));
}
if (o instanceof PrimitiveCircleObject) {
((PrimitiveCircleObject) o).setPartial(partial);
}
if (o instanceof LineObject) {
((LineObject) o).setPartial(partial);
}
} else {
C.Partial = partial;
C.PartialLines = partial;
}
return;
}
if ((NParams == 1 || NParams == 2) && ptest(f, "hide"))
// hide object or toggle show hidden state
{
if (NParams == 1 && !truecheck(params[0])) {
final ConstructionObject o = C.find(params[0]);
if (o == null) {
throw new ConstructionException(Global.name("exception.notfound"));
}
o.setHidden(true);
return;
}
final boolean hidden = truetest(params[0]);
if (NParams == 2) {
final ConstructionObject o = C.find(params[1]);
if (o == null) {
throw new ConstructionException(Global.name("exception.notfound"));
}
o.setHidden(hidden);
} else {
C.Hidden = hidden;
}
return;
}
if (NParams == 2 && ptest(f, "invisible"))
// totally invisible for an object
{
if (NParams == 1 && !truecheck(params[0])) {
final ConstructionObject o = C.find(params[0]);
if (o == null) {
throw new ConstructionException(Global.name("exception.notfound"));
}
o.setSuperHidden(true);
return;
}
final boolean hidden = truetest(params[0]);
if (NParams == 2) {
final ConstructionObject o = C.find(params[1]);
if (o == null) {
throw new ConstructionException(Global.name("exception.notfound"));
}
o.setSuperHidden(hidden);
} else {
throw new ConstructionException(Global.name("exception.notfound"));
}
return;
}
if (NParams >= 1 && ptest(f, "back"))
// push object into background
{
if (NParams == 1) {
final ConstructionObject o = C.find(params[0]);
if (o == null) {
throw new ConstructionException(Global.name("exception.notfound"));
}
o.setBack(true);
return;
}
final boolean back = truetest(params[0]);
final ConstructionObject o = C.find(params[1]);
if (o == null) {
throw new ConstructionException(Global.name("exception.notfound"));
}
o.setBack(back);
return;
}
if (NParams >= 1 && ptest(f, "acute"))
// set acute state of angle, or set default acute state
{
if (NParams == 1 && !truecheck(params[0])) {
final ConstructionObject o = C.find(params[0]);
if (o == null) {
throw new ConstructionException(Global.name("exception.notfound"));
}
o.setObtuse(false);
return;
}
final boolean acute = truetest(params[0]);
if (NParams == 2) {
final ConstructionObject o = C.find(params[1]);
if (o == null) {
throw new ConstructionException(Global.name("exception.notfound"));
}
o.setObtuse(!acute);
} else {
C.Obtuse = !acute;
}
return;
}
if (NParams >= 1 && ptest(f, "obtuse"))
// revorse of acute
{
if (NParams == 1 && !truecheck(params[0])) {
final ConstructionObject o = C.find(params[0]);
if (o == null) {
throw new ConstructionException(Global.name("exception.notfound"));
}
o.setObtuse(false);
return;
}
final boolean obtuse = truetest(params[0]);
if (NParams == 2) {
final ConstructionObject o = C.find(params[1]);
if (o == null) {
throw new ConstructionException(Global.name("exception.notfound"));
}
o.setObtuse(obtuse);
} else {
C.Obtuse = obtuse;
}
return;
}
if (NParams >= 1 && ptest(f, "solid"))
// set solid state of object, or default solid state
{
if (NParams == 1 && !truecheck(params[0])) {
final ConstructionObject o = C.find(params[0]);
if (o == null) {
throw new ConstructionException(Global.name("exception.notfound"));
}
o.setSolid(false);
return;
}
final boolean solid = truetest(params[0]);
if (NParams == 2) {
final ConstructionObject o = C.find(params[1]);
if (o == null) {
throw new ConstructionException(Global.name("exception.notfound"));
}
o.setSolid(solid);
} else {
C.Solid = solid;
}
return;
}
if (NParams == 3 && ptest(f, "restrict"))
// set range for circle arcs
{
try {
final PrimitiveCircleObject c = (PrimitiveCircleObject) C.find(params[0]);
c.setRange(params[1], params[2]);
} catch (final Exception e) {
throw new ConstructionException(Global.name("exception.notfound"));
}
return;
}
if (NParams >= 1 && ptest(f, "fill"))
// set fill state for objects: fill(o), fill(t/f,o)
{
if (NParams == 1) {
final ConstructionObject o = C.find(params[0]);
if (o == null) {
throw new ConstructionException(Global.name("exception.notfound"));
}
o.setFilled(true);
o.setBack(true);
return;
}
final boolean fill = truetest(params[0]);
final ConstructionObject o = C.find(params[1]);
if (o == null) {
throw new ConstructionException(Global.name("exception.notfound"));
}
o.setFilled(fill);
o.setBack(fill);
return;
}
if (NParams >= 1 && ptest(f, "valid"))
// set always valid state of intersection
{
if (NParams == 1) {
final ConstructionObject o = C.find(params[0]);
if (o == null) {
throw new ConstructionException(Global.name("exception.notfound"));
}
if (o instanceof PlumbObject) {
((PlumbObject) o).setRestricted(false);
} else if (o instanceof IntersectionObject) {
((IntersectionObject) o).setRestricted(false);
}
return;
}
truetest(params[0]);
final ConstructionObject o = C.find(params[1]);
if (o == null) {
throw new ConstructionException(Global.name("exception.notfound"));
}
if (o instanceof PlumbObject) {
((PlumbObject) o).setRestricted(false);
} else if (o instanceof IntersectionObject) {
((IntersectionObject) o).setRestricted(false);
}
return;
}
if (NParams >= 1 && (ptest(f, "rename") || ptest(f, "name")))
// works like name
{
if (NParams == 1 && !truecheck(params[0])) {
final ConstructionObject o = C.find(params[0]);
if (o == null) {
throw new ConstructionException(Global.name("exception.notfound"));
}
o.setShowName(true);
return;
}
ConstructionObject o = C.find(params[0]);
if (o == null) {
final boolean shownames = truetest(params[0]);
if (NParams == 2) {
o = C.find(params[1]);
if (o == null) {
throw new ConstructionException(Global.name("exception.notfound"));
}
o.setShowName(truetest(params[0]));
} else {
C.ShowNames = shownames;
}
} else if (!params[1].equals("")) {
o.setName(params[1]);
}
return;
}
if (NParams == 2 && ptest(f, "away"))
// keep interesction away from object
{
final ConstructionObject o = C.find(params[0]);
final ConstructionObject p = C.find(params[1]);
if (!(o instanceof IntersectionObject) || !(p instanceof PointObject)) {
throw new ConstructionException(Global.name("exception.parameter"));
}
((IntersectionObject) o).setAway(p.getName());
return;
}
if (NParams == 2 && ptest(f, "close"))
// keep interesction close to object
{
final ConstructionObject o = C.find(params[0]);
final ConstructionObject p = C.find(params[1]);
if (!(o instanceof IntersectionObject)
|| !(p instanceof PointObject)) {
throw new ConstructionException(Global.name("exception.parameter"));
}
((IntersectionObject) o).setAway(p.getName(), false);
return;
}
if (NParams >= 1 && ptest(f, "value"))
// set the size of an object, value of expression, position of point
// or toggle value display
{
if (NParams == 1 && !truecheck(params[0])) // value(o)
{
final ConstructionObject o = C.find(params[0]);
if (o == null) {
throw new ConstructionException(Global.name("exception.notfound"));
}
o.setShowValue(true);
return;
}
ConstructionObject o = C.find(params[0]);
if (o == null) // value(t/f), value(t/f,o)
{
try {
truetest(params[0]);
} catch (final Exception e) {
throw new ConstructionException(Global.name("exception.notfound"));
}
if (NParams == 2) {
o = C.find(params[1]);
if (o == null) {
throw new ConstructionException(Global.name("exception.notfound"));
}
o.setShowValue(truetest(params[0]));
} else {
C.ShowValues = true;
}
} else if (NParams == 2) // value(o,x)
{
if (o instanceof SegmentObject) {
final SegmentObject os = (SegmentObject) o;
if (!os.canFix()) {
throw new ConstructionException(Global.name("exception.canfix"));
}
os.setFixed(true, params[1]);
os.validate();
} else if (o instanceof CircleObject) {
final CircleObject os = (CircleObject) o;
if (!os.canFix()) {
throw new ConstructionException(Global.name("exception.canfix"));
}
os.setFixed(true, params[1]);
os.validate();
} else if (o instanceof FixedCircleObject) {
final FixedCircleObject os = (FixedCircleObject) o;
os.setFixed(params[1]);
os.validate();
} else if (o instanceof AngleObject) {
final AngleObject os = (AngleObject) o;
if (!os.canFix()) {
throw new ConstructionException(Global.name("exception.canfix"));
}
os.setFixed(params[1]);
os.validate();
} else if (o instanceof FixedAngleObject) {
final FixedAngleObject os = (FixedAngleObject) o;
os.setFixed(params[1]);
os.validate();
} else if (o instanceof ExpressionObject) {
final ExpressionObject os = (ExpressionObject) o;
os.setFixed(params[1]);
os.validate();
} else {
throw new ConstructionException(Global.name("exception.parameter"));
}
} else if (NParams == 3) // value(P,x,y)
{
if (o instanceof PointObject) {
final PointObject os = (PointObject) o;
if (!os.moveablePoint()) {
throw new ConstructionException(Global.name("exception.canfix"));
}
os.setFixed(params[1], params[2]);
os.validate();
} else {
throw new ConstructionException(Global.name("exception.parameter"));
}
} else {
throw new ConstructionException(Global.name("exception.parameter"));
}
return;
}
// Look for the normal construction functions:
final int i = findFunction(function, zc);
if (i >= 0) {
for (int j = 0; j < NParams; j++) {
params[j] = extend(params[j]);
}
OCs[i].construct(C, name, params, NParams);
// the following are for macro definition in scripts
if (Parameter) {
if (VN >= V.size()) {
throw new ConstructionException(Global.name("exception.macroparameter"));
}
final ConstructionObject o = C.lastButN(0);
o.setMainParameter(true);
if (o.isMainParameter()) {
C.addParameter(o);
C.Prompts.addElement(comment);
} else {
throw new ConstructionException(Global.name("exception.macroparameter"));
}
} else if (Target) {
if (VN + 1 != V.size()) {
throw new ConstructionException(Global.name("exception.macrotarget"));
}
final ConstructionObject o = C.lastButN(0);
o.setTarget(true);
C.addTarget(o);
} else if (Prompt) {
final ConstructionObject o = C.lastButN(0);
C.PromptFor.addElement(o.getName());
}
return;
}
// Finally, look for macros:
final Macro m = zc.chooseMacro(function);
if (m == null) {
throw new ConstructionException(Global.name("exception.function"));
}
MR.setMacro(m, zc);
// System.out.println("nom:"+m.getName());
MR.run(zc, C, name, params, NParams);
// Only for macro definition in scripts
if (Target) {
final ConstructionObject o = C.find(name);
if (o == null) {
throw new ConstructionException(Global.name("exception.macrotarget"));
}
o.setTarget(true);
C.addTarget(o);
} else if (Prompt) {
final ConstructionObject o = C.find(name);
if (o != null) {
C.PromptFor.addElement(o.getName());
}
}
}
public void interpret(final ZirkelCanvas zc, final String s)
throws ConstructionException {
interpret(zc, s, "");
}
static public boolean truetest(String s) throws ConstructionException {
s = s.toLowerCase();
if (s.equals("true") || s.equals(Global.name("true"))) {
return true;
}
if (s.equals("false") || s.equals(Global.name("false"))) {
return false;
}
throw new ConstructionException(Global.name("exception.boolean"));
}
static public boolean truecheck(String s) {
s = s.toLowerCase();
if (s.equals("true") || s.equals(Global.name("true"))) {
return true;
}
if (s.equals("false") || s.equals(Global.name("false"))) {
return true;
}
return false;
}
static public boolean test(final String f, final String tag, final String s) {
return f.equalsIgnoreCase(Global.name(tag + "." + s, ""))
|| f.equals(Global.name(tag + ".short." + s, ""))
|| f.equals(Global.name(tag + "." + s + ".short", ""))
|| f.equalsIgnoreCase(s);
}
static public int startTest(final String tag, final String s) {
int i = startTest0(Global.name(tag, tag).toLowerCase(), s.toLowerCase());
if (i > 0) {
return i;
}
i = startTest0(Global.name(tag + ".short", tag), s);
if (i > 0) {
return i;
}
return startTest0(tag, s.toLowerCase());
}
static public int startTest0(final String tag, final String s) {
if (s.startsWith(tag + " ")) {
return tag.length() + 1;
}
return -1;
}
static public boolean ptest(final String f, final String s) {
return test(f, "function", s);
}
static public boolean nametest(final String f, final String s) {
return test(f, "name", s);
}
/**
* Works like find, but can interpret c(k), p1(s), p2(s) etc.
*/
public String extend(String s) {
if (s.startsWith("c(") && s.endsWith(")")) {
s = s.substring(2, s.length() - 1);
final ConstructionObject o = C.find(s);
if (o instanceof PrimitiveCircleObject) {
return ((PrimitiveCircleObject) o).getP1().getName();
}
} else if (s.startsWith("a(") && s.endsWith(")")) {
s = s.substring(2, s.length() - 1);
final ConstructionObject o = C.find(s);
if (o instanceof TwoPointLineObject) {
return ((TwoPointLineObject) o).getP1().getName();
}
} else if (s.startsWith("b(") && s.endsWith(")")) {
s = s.substring(2, s.length() - 1);
final ConstructionObject o = C.find(s);
if (o instanceof TwoPointLineObject) {
return ((TwoPointLineObject) o).getP2().getName();
}
}
return s;
}
MacroRunner MR = new MacroRunner();
static ObjectConstructor OCs[] = { new PointConstructor(),
new SegmentConstructor(), new LineConstructor(),
new RayConstructor(), new CircleConstructor(),
new IntersectionConstructor(), new ParallelConstructor(),
new PlumbConstructor(), new MidpointConstructor(),
new AngleConstructor(), new AreaConstructor(),
new QuadricConstructor(), new ExpressionConstructor(),
new FunctionConstructor() };
static public String ONs[] = { "point", "segment", "line", "ray", "circle",
"intersection", "parallel", "plumb", "angle", "area",
"quadric", "expression", "function","text" };
static public int findFunction(final String function, final ZirkelCanvas zc) {
for (int i = 0; i < OCs.length; i++) {
if (nametest(function, OCs[i].getTag()) && zc.enabled(ONs[i])) {
return i;
}
}
return -1;
}
}