Do you know why when declaring local const vars, the script cannot compile?
Sorry, I know very little pascal and cannot figure out why this is not working!
This example (see function CircleArea) shows that my syntax should be fine.
http://www.tutorialspoint.com/pascal/pascal_quick_guide.htm
This is what I am trying to do:
//---placed within [Code]
procedure MyLog(const _functionName, _msg: String);
begin
Log(_functionName + '(): ' + _msg);
end;
function MyExec(const _filename, _params, _dir: String): Boolean;
const // <--- compilation fails in this line!
MethodName = 'MyExec';
var
ResultCode: Integer;
begin
MyLog(MethodName, _filename);
// ... invoke Exec(), etc. ...
end;
//---
You were trying that right. If Inno Setup were using Pascal it would even work, but since it is based on a custom Pascal Script language with limitation on declaring local constants, you can't do it that way. You must define your constant globally instead:
[Code]
const
MethodName = 'MyExec';
function MyExec(const _filename, _params, _dir: String): Boolean;
var
ResultCode: Integer;
begin
MyLog(MethodName, _filename);
// ... invoke Exec(), etc. ...
end;
You can use #define to define "local" constants and then use ExpandConstant('{#ConstantName}') whenever you need the value of that constant.
function MyExec(const _filename, _params, _dir: String): Boolean;
var
ResultCode: Integer;
begin
#define MethodName 'MyExec'
MyLog(ExpandConstant('{#MethodName}'), _filename);
// ... invoke Exec(), etc. ...
end;
Note that the constant isn't actually local, because it is just a preprocessor definition. So the functions after MyExec could refer to the constant as well, which might be a potential cause of error (but isn't worse than defining a real global constant). You can redefine the same constant in another function or procedure without causing a compile error though.
function MyExec(const _filename, _params, _dir: String): Boolean;
begin
#define MethodName 'MyExec'
MyLog(ExpandConstant('{#MethodName}'), _filename);
end;
function MyExec2(const _filename, _params, _dir: String): Boolean;
begin
// if you forget to put the next line, it will log 'MyExec'!!!
#define MethodName 'MyExec2'
MyLog(ExpandConstant('{#MethodName}'), _filename);
end;
For added safety, you might want to #undef the "local" constant at the end of the function, in which case InnoSetup would cause a compile error if you'd try to reference it in the next function.
function MyExec(const _filename, _params, _dir: String): Boolean;
begin
#define MethodName 'MyExec'
MyLog(ExpandConstant('{#MethodName}'), _filename);
#undef MethodName
end;
function MyExec2(const _filename, _params, _dir: String): Boolean;
begin
// Forgot to define MethodName, but InnoSetup will cause an error
// "undeclared identifier: MethodName".
MyLog(ExpandConstant('{#MethodName}'), _filename);
end;
Related
Is overloading of implicit type conversion possible for enumerations in Delphi?
program TriState;
type
TTrilean = (trNone = -1, trFalse = 0, trTrue = 1);
TTrileanHelper = record helper for TTrilean
public
class operator Implicit(...)...; //E2123 PROCEDURE, FUNCTION, PROPERTY, or VAR expected
end;
var
v: TTrilean;
begin
v := trNone;
v := True; //Would like to have class operator Implicit here
end.
In the Delphi 10.4.2 documentation I read:
Note: Class and record helpers do not support operator overloading.
I have this module
defmodule ElixirMeta.LangLoader do
#external_resource [Path.join([__DIR__, "es.json"]),
Path.join([__DIR__, "en.json"])]
defmacro __using__(_) do
for lang <- ["es", "en"] do
{:ok, body} = File.read(Path.join([__DIR__, "#{lang}.json"]))
{:ok, json} = Poison.decode(body)
quote do
def lang(unquote(lang)), do: unquote(Macro.escape(json))
end
end
end
end
defmodule ElixirMeta.Lang do
use ElixirMeta.LangLoader
end
I know I can define a function like:
def lang(unquote(lang)), do: unquote(Macro.escape(json))
And can be called like this:
Lang.lang("es")
Also even modify it's function name, like this:
def unquote(:"lang_#{lang}")(), do: unquote(Macro.escape(json))
And be called like this:
Lang.lang_es
But is it possible to do the same with a module attribute?
And being the module attribute compiled (?) I think is not possible to initialize it from the macro? maybe I would have to do it within before_compile macro?
I would like to access, for the purpose of the example, Lang.lang_es as a #lang_es and #lang_en LangLoader attributes
Yes, one can achieve that with Module.put_attribute/3 (I have created an MCVE out of your initial code):
defmodule ElixirMeta.LangLoader do
defmacro __using__(_) do
[
(quote do: Module.register_attribute __MODULE__,
:langs, accumulate: true) |
for lang <- ["es", "en"] do
quote do
def lang(unquote(lang)), do: unquote(lang)
Module.put_attribute __MODULE__,
:"lang_#{unquote(lang)}", unquote(lang)
Module.put_attribute __MODULE__,
:langs, unquote(lang)
end
end
]
end
end
defmodule ElixirMeta.Lang do
use ElixirMeta.LangLoader
def test do
IO.inspect {
#lang_es,
Enum.find(#langs, & &1 == "es"),
lang("es")
}, label: "Variants"
end
end
ElixirMeta.Lang.test
#⇒ Variants: {"es", "es", "es"}
The code above declares the accumulated attribute (#attr :foo followed by #attr :bar would produce [:foo, :bar] value instead of overwriting the attribute value, single attribute and the function.
Please note, that there is no way to access module attribute from outside, since module attributes are compile-time entities.
Both of the following function definations compile even though one uses = and other doesn't. Why? Is there an advantage of this behaviour?
def 1
def doWork(index:Int) = {
sleep((math.random*1000).toLong);
index;
}
def 2
def doWork(index:Int) {
sleep((math.random*1000).toLong);
index;
}
def 1 is what you want to use.
def 2 is called procedure syntax (discouraged) and actually means this:
def doWork(index:Int): Unit = {
sleep((math.random*1000).toLong)
index
}
So it's probably now what you want (since it doesn't return anything).
Not including an = sign declares a procedure. Procedures return Unit, i.e., don't return a value at all. As explained in the Scala language specification (from the link above):
A procedure definition is a function definition where the result type and the equals sign are omitted; its defining expression must be a block. E.g., def f(ps) {stats} is equivalent to def f(ps): Unit = {stats}.
In your second case, the return value simply gets suppressed to turn a function that returns Int into a procedure that returns Unit. While doing so, the compiler should issue a warning similar to
warning: a pure expression does nothing in a statement position
This should let you know that something fishy is going on, i.e., there is a statement that would normally result in the block returning a value (index; in your case), but it goes unused.
When you don't use "=" with def, it means your defined function will return unit.
And in the second function, you don't use "=", that means the defined function will return unit, but your function is returning index.
That's why it throws warning as it expects unit and discard the value.
Thanks
I want to instantiate a package and pass functions to it that overload operators in order to make a Generic Binary Search Tree. Here's the specifications.
bstgen.ads (snippet)
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Unchecked_Deallocation;
GENERIC
type Akey is private;
type TreeRecord is private;
with function "<"(K: in Akey; R: in TreeRecord) return Boolean;
with function ">"(K: in Akey; R: in TreeRecord) return Boolean;
with function "="(K: in Akey; R: in TreeRecord) return Boolean;
PACKAGE BSTGen IS
TYPE St10 IS NEW String(1..10);
TYPE TreePt IS PRIVATE;
PACKAGE EnumIO IS NEW Ada.Text_IO.Enumeration_IO(Akey); USE EnumIO;
driver.adb (snippet)
with Ada.Text_IO; use Ada.Text_IO;
WITH BSTGen;
PROCEDURE Driver IS
IP: Integer := 1;
TYPE Names IS (Resig,Keene,Marsden,Vuijic,Marcus,Gonzalez);
PACKAGE NamesIO IS NEW Ada.Text_IO.Enumeration_IO(Names);
type St10 is NEW String(1..10);
type Customer is
record Name: Names;
PhoneNumber: St10;
end record;
function "<"(K: in Names; R: in Customer) return Boolean is begin
return K < R.Name;
end "<";
function ">"(K: in Names; R: in Customer) return Boolean is begin
return K > R.Name;
end ">";
function "="(K: in Names; R: in Customer) return Boolean is begin
return K = R.Name;
end "=";
PACKAGE IntIO IS NEW Ada.Text_IO.Integer_IO(Integer); USE IntIO;
PACKAGE mybst is NEW BSTGen(Names,Customer,<,>,=); USE mybst;
R, Pt: TreePt;
Name: Names;
Phone: St10;
Status: Boolean;
BEGIN
R := CreateTree;
Pt := R;
However, when I try to compile, this is the output:
driver.adb:24:04: expect subprogram or entry name in instantiation of "<"
driver.adb:24:04: instantiation abandoned
bstgen.ads:19:53: expect discrete type in instantiation of "Enum"
bstgen.ads:19:53: instantiation abandoned
This includes a bunch of errors stating that driver.adb's methods are not visible, which is to be expected as the instantiation of mybst is abandoned. How do I fix this?
In bstgen.ads, you say
PACKAGE EnumIO IS NEW Ada.Text_IO.Enumeration_IO(Akey);
but in the generic formal part you said
type Akey is private;
which means that the compiler can assume very little about the actual type except that equality and assignment are available. It could be a record of hundreds of bytes; it certainly need not be an enumeration.
To ensure that Akey is an enumeration, you need to say
type Akey is (<>);
as in ARM12.5(13).
In driver.adb, you say
PACKAGE mybst is NEW BSTGen(Names,Customer,<,>,=);
which should read
PACKAGE mybst is NEW BSTGen(Names,Customer,”<“,”>”,”=“);
This is a bit of an extension on another of my questions. I've got a DLL that is supposed to interface with Game Maker, which uses Double and PChar.
I have to convert my objects to Doubles (references) to pass back and forth with Game Maker.
I have 2 Classes: TBitmap and TWindow. Each implements IBlittable. This means that methods operating on IBlittables can use both, however here's the problem:
Here's how I create them:
{Creation of Bitmaps and Windows}
function CreateBitmap(W, H: Double): Double; STDCall;
var
TBM: TBitmap;
begin
TBM := TBitmap.Create(Floor(W), Floor(H));
CreateBitmap := Double(Integer(TBM));
end;
function GetWindowByHWND(Handle: Double): Double; STDCall;
var
ReturnVal: TWindow;
begin
ReturnVal := TWindow.Create(Floor(Handle));
GetWindowByHWND := Double(Integer(ReturnVal));
end;
And here's how I am trying to operate on them:
function SetPixel(Handle, X, Y, Color: Double): Double; STDCall;
var
<stuff>
begin
Blittable := IBlittable(Floor(Handle)); //This!
<set the pixel>
SetPixel := 0;
end;
When I cast the Floor(Handle) to IBlittable, it segfaults and crashes.
When I cast it to what it previously was (a TWindow or a TBitmap) it works fine. How do I circumvent this problem?
I really don't want to rewrite all the methods specifically (that'd be pretty redundant and lame)
I needed to change the types in the creation functions:
function CreateBitmap(W, H: Double): Double; STDCall;
var
TBM: IBlittable; //See
begin
TBM := TBitmap.Create(Floor(W), Floor(H));
CreateBitmap := Double(Integer(TBM));
end;
function GetWindowByHWND(Handle: Double): Double; STDCall;
var
ReturnVal: IBlittable; //Here too
begin
ReturnVal := TWindow.Create(Floor(Handle));
GetWindowByHWND := Double(Integer(ReturnVal));
end;