From f2702a50a2b7e27ba46c44101edfc737f8eb54ac Mon Sep 17 00:00:00 2001 From: "Benjamin J. Culkin" Date: Sat, 17 Oct 2020 17:13:23 -0300 Subject: Implement float printing This implements a general directive for float printing (~`D). In the long term, instead of this directive, a more specific one (probably implemented by a macro or something) should be used --- .../java/bjc/utils/ioutils/format/CLFormatter.java | 24 +++++- .../format/directives/DecimalDirective.java | 89 ++++++++++++++++++++++ 2 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 clformat/src/main/java/bjc/utils/ioutils/format/directives/DecimalDirective.java (limited to 'clformat/src/main') diff --git a/clformat/src/main/java/bjc/utils/ioutils/format/CLFormatter.java b/clformat/src/main/java/bjc/utils/ioutils/format/CLFormatter.java index 9263beb..db137a5 100644 --- a/clformat/src/main/java/bjc/utils/ioutils/format/CLFormatter.java +++ b/clformat/src/main/java/bjc/utils/ioutils/format/CLFormatter.java @@ -70,6 +70,8 @@ public class CLFormatter { builtinDirectives.put("`[", new InflectDirective()); builtinDirectives.put("T", new TabulateDirective()); + + builtinDirectives.put("`D", new DecimalDirective()); } /** @@ -101,13 +103,31 @@ public class CLFormatter { */ public static void checkItem(Object itm, char directive) { if (itm == null) { - String msg - = String.format("No argument provided for %c directive", directive); + String msg = String.format("No argument provided for %c directive", directive); throw new IllegalArgumentException(msg); } } + /** + * Check that an item is valid for a directive. + * + * @param itm + * The item to check. + * + * @param directive + * The directive to check for. + * + * @throws IllegalArgumentException + * if itm is null. + */ + public static void checkItem(Object itm, String directive) { + if (itm == null) { + String msg = String.format("No argument provided for %s directive", directive); + + throw new IllegalArgumentException(msg); + } + } /** * Format a string in the style of CL's FORMAT. * diff --git a/clformat/src/main/java/bjc/utils/ioutils/format/directives/DecimalDirective.java b/clformat/src/main/java/bjc/utils/ioutils/format/directives/DecimalDirective.java new file mode 100644 index 0000000..1130a85 --- /dev/null +++ b/clformat/src/main/java/bjc/utils/ioutils/format/directives/DecimalDirective.java @@ -0,0 +1,89 @@ +package bjc.utils.ioutils.format.directives; + +import java.io.*; +import java.text.*; + +import bjc.esodata.*; +import bjc.utils.ioutils.format.*; + +/** + * Implementation of the `D directive. + * + * This is the most general directive for printing out decimal-numbers (floating + * point). + * + * @author Ben Culkin + */ +public class DecimalDirective implements Directive { + @Override + public Edict compile(CompileContext compCTX) { + CLParameters params = compCTX.decr.parameters; + CLModifiers mods = compCTX.decr.modifiers; + + CLValue decForm = CLValue.nil(); + + switch(params.length()) { + case 0: + // Use the default + break; + case 1: + // Use the specified format + params.mapIndices("format"); + + decForm = params.resolveKey("format"); + break; + default: + // @TODO 16 Oct, 2020 - Ben Culkin - :Preformat + // Add ability to specify a common/fixed set of formats + // + // @TODO 16 Oct, 2020 - Ben Culkin - :ErrorFix + // Instead of using IllegalArgumentException here, use a custom + // subtype of it with an appropriate name/auto-message forming + throw new IllegalArgumentException("Must provide 0 or 1 arguments to `D directive"); + } + + return new DecimalEdict(decForm); + } +} + +class DecimalEdict implements Edict { + private static final FieldPosition ZERO_FIELD = new FieldPosition(0); + + private CLValue decFormat; + + public DecimalEdict(CLValue decForm) { + this.decFormat = decForm; + } + + @Override + public void format(FormatContext formCTX) throws IOException { + Tape itemTape = formCTX.items; + + CLFormatter.checkItem(itemTape.item(), "`D"); + + NumberFormat numForm = NumberFormat.getInstance(); + + String decFormString = decFormat.getValue(itemTape); + + if (decFormString == null || decFormString.equals("")) { + // Use the default if not provided. + } else { + if (numForm instanceof DecimalFormat) { + ((DecimalFormat)numForm).applyPattern(decFormString); + } else { + String clsName = numForm.getClass().getName(); + + String msg = String.format("INTERNAL ERROR: Unknown NumberFormat type %s, expected DecimalFormat or compatible", clsName); + + throw new UnsupportedOperationException(msg); + } + } + + StringBuffer work = new StringBuffer(); + + numForm.format(itemTape.item(), work, ZERO_FIELD); + + formCTX.writer.write(work.toString()); + itemTape.right(); + } +} -- cgit v1.2.3