[mercury-users] Re: Handy Programming tool for Mercury.

Ralph Becket rwab1 at cam.sri.com
Tue May 11 21:57:30 AEST 1999


True to form, I forgot to attach the file...  here it is.

Ralph

-- 
Ralph Becket  |  rwab1 at cam.sri.com  |  http://www.cam.sri.com/people/becket.html
-------------- next part --------------
#! /usr/local/bin/gawk -f

# ------------------------------------------------------------------------------
# state2m	Mon May 10 BST 1999	Ralph Becket <rwab1 at cl.cam.ac.uk>
# ------------------------------------------------------------------------------
#
# Tool to help automate the construction of `state containers' in
# Mercury.
#
# This program preprocesses a file as follows.  Any lines that do not
# start with a `*' are passed straight through.  Lines that start with
# a `*' must obey the grammar below.
#
# A type is declared to the preprocessor with
# 	* type type_name[(.*)] [different_constructor_name]
# followed by zero or more lines of
# 	*  field_name field_type fieldproperty* [% comment]
# where fieldproperty abbreviates [readonly | mutable | private | func]
# followed by a blank line.
#
# Code is generated with the following:
# 	* typespec type_name
# 	* predspec type_name
# 	* implementation type_name
#
# By default a field is taken to be RW, accessed and updated via
# predicates of spec
# 	:- pred field_name(type_name::in, field_type::out) is det.
# 	:- pred set_field_name(type_name::in,field_type::in,field_type::out)
# 			is det.
# respectively.
#
# If a field has property mutable, but not func, then it also has a
# predicate of spec
# 	:- pred chg_field_name(type_name::in,
# 			(pred(field_type::in, field_type::out) is det)::in,
# 			type_name::out) is det.
#
# If a field has property mutable and also func, then it also has a
# function of spec
# 	:- func chg_field_name(type_name, func(field_type) = field_type) =
# 			type_name.
#
# If a field has property readonly then the set_field_name predicate is not
# generated (nor is the chg_field_name predicate if the field is
# mutable).
#
# If a field has property func then the above predicates are instead
# implemented with functions with spec
# 	:- func field_name(type_name) = field_type.
# 	:- func set_field_name(type_name, field_type) = type_name.
#
# If a field has property private then it will not be declared in the
# predinterface section, but rather the implementation section.
#
# ------------------------------------------------------------------------------

$1 != "*" { print $0; in_type_spec = 0; next }

{ print "% "$0 }

$2 == "type" {

	if(NF < 3 || 4 < NF) {
		warn("syntax error: expected\n* type type_name[(.*)] [differentconstructor_name]\n              found\n"$0)
		exit 1
	}

	type_decl_name = $3
	type_name = $3
	sub("\\(.*", "", type_name)

	constructor_name = ( NF == 4 ? $4 : type_name )

	if(type_name in type_names) {
		warn("name error: type name used twice: "type_name)
		exit 1
	}

	ntype = ntypes++

# print ntype, type_name, type_decl_name, constructor_name

	type_names[ntype] = type_name
	type_decl_names[ntype] = type_decl_name
	constructor_names[ntype] = constructor_name

	in_type_spec = 1

	next
}

in_type_spec {

	comment = $0
	sub("^[^%]*", "", comment)
	sub("%.*", "", $0)

	if(NF < 3) {
		warn("syntax error: expected\n* field_name field_type fieldproperty* [% comment]\n found\n"$0 comment)
		exit 1
	}

	field_name = $2
	field_type = $3

	if((type_name,field_name) in field_names) {
		warn("name error: field name used twice in same type: "field_name)
		exit 1
	}
	field_names[type_name,field_name]

	nfield = nfields[ntype]++

# print ntype, type_name, nfield, field_name, field_type

	field_names[ntype,nfield] = field_name
	field_types[ntype,nfield] = field_type

	for(i = 4; i <= NF; i++) {
		if($i == "readonly") {
			is_readonly[ntype,nfield] = 1
		}
		else if($i == "mutable") {
			is_mutable[ntype,nfield] = 1
		}
		else if($i == "func") {
			is_function[ntype,nfield] = 1
		}
		else if($i == "private") {
			is_private[ntype,nfield] = 1
		}
		else {
			warn("syntax error: field property must be one of readonly, mutable, private, or func\n              found: "$i)
			exit 1
		}
	}

	next
}

$2 == "typespec" {

	if(NF != 3) {
		warn("syntax error: expected\n* typespec type_name\n              found\n"$0)
		exit 1
	}
	type_name = $3

	for(i = 0; i < ntypes; i++) {
		if(type_names[i] == type_name) {
			ntype = i
			break
		}
	}
	if(i == ntypes) {
		warn("name error: unrecognised type name: "type_name)
		exit 1
	}

# print ntype, type_name, nfields[ntype], type_decl_names[ntype]

	print ""
	if(nfields[ntype] == 0) {
		print ":- type "type_decl_names[ntype]" ---> "constructor_names[ntype]"."
	}
	else {
		print ":- type "type_decl_names[ntype]" ---> \n\t"constructor_names[ntype]"("
		for(i = 0; i < nfields[ntype]; i++) {
			print "\t\t"field_types[ntype,i] \
				( i + 1 == nfields[ntype] ? "" : "," )
		}
		print "\t)."
	}

	next
}

$2 == "predspec" {

	if(NF != 3) {
		warn("syntax error: expected\n* predspec type_name\n              found\n"$0)
		exit 1
	}
	type_name = $3

	for(i = 0; i < ntypes; i++) {
		if(type_names[i] == type_name) {
			ntype = i
			break
		}
	}
	if(i == ntypes) {
		warn("name error: unrecognised type name: "type_name)
		exit 1
	}

	print ""
	for(i = 0; i < nfields[ntype]; i++) {
		if(! is_private[ntype,i]) {
			print public_spec(ntype, i)
		}
	}

	next
}

$2 == "implementation" {

	if(NF != 3) {
		warn("syntax error: expected\n* implementation type_name\n              found\n"$0)
		exit 1
	}
	type_name = $3

	for(i = 0; i < ntypes; i++) {
		if(type_names[i] == type_name) {
			ntype = i
			break
		}
	}
	if(i == ntypes) {
		warn("name error: unrecognised type name: "type_name)
		exit 1
	}

	print ""
	for(i = 0; i < nfields[ntype]; i++) {
		print implementation(ntype, i)
	}

	next
}

{
	warn("syntax error: unrecognised syntax\n                  found\n"$0)
	exit 1
}

function public_spec(ntype, nfield,    s, tf) {

	tf = ntype SUBSEP nfield

	s = ""

	if(! is_private[tf]) {
		s = s get_spec(ntype, nfield)
		if(! is_readonly[tf]) {
		s = s set_spec(ntype, nfield)
		}
		if(is_mutable[tf]) {
			s = s mut_spec(ntype, nfield)
		}
	}
	
	return s
}

function private_spec(ntype, nfield,    s, tf) {

	tf = ntype SUBSEP nfield

	s = ""

	if(is_private[tf]) {
		s = s "\n"get_spec(ntype, nfield)
		s = s set_spec(ntype, nfield)
		if(is_mutable[tf]) {
			s = s mut_spec(ntype, nfield)
		}
	}
	else if(is_readonly[tf]) {
		s = s set_spec(ntype, nfield)
	}

	return s
}

function get_spec(ntype, nfield,    s, tf, isfn) {

	tf = ntype SUBSEP nfield
	isfn = is_function[tf]

	s = ":- "( isfn ? "func " : "pred ")field_names[tf]"("
	s = s type_decl_names[ntype]
	s = s ( isfn ? ") = "field_types[tf]".\n" : ", "field_types[tf]").\n" )
	s = s ( isfn ? "" : ":- mode "field_names[tf]"(in, out) is det.\n" )

	return s
}

function set_spec(ntype, nfield,    s, tf, isfn) {

	tf = ntype SUBSEP nfield
	isfn = is_function[tf]

	s = ":- "( isfn ? "func " : "pred ")"set_"field_names[tf]"("
	s = s type_decl_names[ntype]", "field_types[tf]
	s = s ( isfn ? ") = "type_decl_names[ntype]".\n" : ", "type_decl_names[ntype]").\n" )
	s = s ( isfn ? "" : ":- mode set_"field_names[tf]"(in, in, out) is det.\n" )

	return s
}

function mut_spec(ntype, nfield,    s, tf, isfn, pt, pm) {

	tf = ntype SUBSEP nfield
	isfn = is_function[tf]
	if(isfn) {
		pt = "func("field_types[tf]") = "field_types[tf]
		pm = ""
	}
	else {
		pt = "pred("field_types[tf]", "field_types[tf]")"
		pm = "pred(in, out) is det"
	}

	s = ":- "( isfn ? "func " : "pred ")"chg_"field_names[tf]"("
	s = s type_decl_names[ntype]", "pt
	s = s ( isfn ? ") = "type_decl_names[ntype]".\n" : ", "type_decl_names[ntype]").\n" )
	s = s ( isfn ? "" : ":- mode chg_"field_names[tf]"(in, "pm", out) is det.\n" )

	return s
}

function implementation(ntype, nfield,    s, tf, ismut) {

	tf = ntype SUBSEP nfield
	ismut = is_mutable[tf]

	s = private_spec(ntype, nfield)"\n"
	s = s get_implementation(ntype, nfield)"\n\n"
	s = s set_implementation(ntype, nfield)"\n"
	if(ismut) {
		s = s "\n"mut_implementation(ntype, nfield)"\n"
	}

	return s
}

function get_implementation(ntype, nfield,    s, tf, isfn) {

	tf = ntype SUBSEP nfield
	isfn = is_function[tf]

	s = field_names[tf]"("select_nth_arg(ntype, nfield, "X")
	s = s ( isfn ? ") = X." : ", X)." )

	return s
}

function set_implementation(ntype, nfield,    s, r, tf, isfn) {

	tf = ntype SUBSEP nfield
	isfn = is_function[tf]
	r = replace_nth_arg(ntype, nfield, "X")

	s = "set_"field_names[tf]"("select_but_nth_arg(ntype, nfield)", X"
	s = s ( isfn ? ") = "r"." : ", "r")." )

	return s
}

function mut_implementation(ntype, nfield,    s, r, tf, isfn) {

	tf = ntype SUBSEP nfield
	isfn = is_function[tf]
	replace_nth_arg(ntype, nfield, "Y")

	s = "chg_"field_names[tf]"("replace_nth_arg(ntype, nfield, "X")", F"

	if(isfn) {
		s = s ") = "replace_nth_arg(ntype, nfield, "F(X)")"."
	}
	else {
		s = s ", "replace_nth_arg(ntype, nfield, "Y")") :-\n"
		s = s "\tF(X, Y)."
	}

	return s
}

function select_nth_arg(ntype, nfield, arg,    s, i) {

	for(i = 0; i < nfields[ntype]; i++) {
		s = s ( i == nfield ? arg : "_" )
		s = s ( i+1 < nfields[ntype] ? ", " : "" )
	}

	return type_names[ntype]"("s")"
}

function select_but_nth_arg(ntype, nfield, arg,    s, i) {

	for(i = 0; i < nfields[ntype]; i++) {
		s = s ( i == nfield ? "_" : "X"i )
		s = s ( i+1 < nfields[ntype] ? ", " : "" )
	}

	return type_names[ntype]"("s")"
}

function replace_nth_arg(ntype, nfield, arg,    s, i) {

	for(i = 0; i < nfields[ntype]; i++) {
		s = s ( i == nfield ? arg : "X"i )
		s = s ( i+1 < nfields[ntype] ? ", " : "" )
	}

	return type_names[ntype]"("s")"
}

function warn(s) {

	print FILENAME":"FNR":"s > "/dev/stderr"
}


More information about the users mailing list