/* Copyright (C) 2003-2013 Runtime Revolution Ltd.
 
 This file is part of LiveCode.
 
 LiveCode is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License v3 as published by the Free
 Software Foundation.
 
 LiveCode 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 LiveCode.  If not see <http://www.gnu.org/licenses/>.  */

/*
This library consists of the operations on codeunits included in the standard library of LiveCode Builder.
*/

module com.livecode.codeunit

use com.livecode.foreign

public foreign handler MCCodeunitFetchCodeunitOf(in Index as LCIndex, in Target as String, out Value as String) returns nothing binds to "<builtin>"
public foreign handler MCCodeunitStoreCodeunitOf(in Value as String, in Index as LCIndex, inout Target as String) returns nothing binds to "<builtin>"
public foreign handler MCCodeunitFetchCodeunitRangeOf(in Start as LCIndex, in Finish as LCIndex, in Target as String, out Value as String) returns nothing binds to "<builtin>"
public foreign handler MCCodeunitStoreCodeunitRangeOf(in Value as String, in Start as LCIndex, in Finish as LCIndex, inout Target as String) returns nothing binds to "<builtin>"

public foreign handler MCCodeunitEvalNumberOfCodeunitsIn(in Target as String, out Count as LCUIndex) returns nothing binds to "<builtin>"

public foreign handler MCCodeunitEvalIsAmongTheCodeunitsOf(in Needle as String, in Target as String, out Value as CBool) returns nothing binds to "<builtin>"

public foreign handler MCCodeunitStoreBeforeCodeunitOf(in Value as String, in Index as LCIndex, inout Target as String) returns nothing binds to "<builtin>"
public foreign handler MCCodeunitStoreAfterCodeunitOf(in Value as String, in Index as LCIndex, inout Target as String) returns nothing binds to "<builtin>"

public foreign handler MCCodeunitEvalOffsetOfCodeunits(in IsLast as CBool, in Needle as String, in Target as String, out Offset as LCUIndex) returns nothing binds to "<builtin>"
public foreign handler MCCodeunitEvalOffsetOfCodeunitsBefore(in IsLast as CBool, in Needle as String, in Before as LCIndex, in Target as String, out Offset as LCUIndex) returns nothing binds to "<builtin>"
public foreign handler MCCodeunitEvalOffsetOfCodeunitsAfter(in IsFirst as CBool, in Needle as String, in After as LCIndex, in Target as String, out Offset as LCUIndex) returns nothing binds to "<builtin>"

public foreign handler MCCodeunitEvalContains(in Source as String, in Needle as String, out Result as CBool) returns nothing binds to "<builtin>"
public foreign handler MCCodeunitEvalBeginsWith(in Source as String, in Prefix as String, out Result as CBool) returns nothing binds to "<builtin>"
public foreign handler MCCodeunitEvalEndsWith(in Source as String, in Suffix as String, out Result as CBool) returns nothing binds to "<builtin>"

public foreign handler MCCodeunitRepeatForEachCodeunit(inout Iterator as optional Pointer, out Iterand as String, in Container as String) returns CBool binds to "<builtin>"

public foreign handler MCCodeunitFetchFirstCodeunitOf(in Target as String, out Value as String) returns nothing binds to "<builtin>"
public foreign handler MCCodeunitStoreFirstCodeunitOf(in Value as String, inout Target as String) returns nothing binds to "<builtin>"

public foreign handler MCCodeunitFetchLastCodeunitOf(in Target as String, out Value as String) returns nothing binds to "<builtin>"
public foreign handler MCCodeunitStoreLastCodeunitOf(in Value as String, inout Target as String) returns nothing binds to "<builtin>"

public foreign handler MCCodeunitExecDeleteCodeunitOf(in Index as LCIndex, inout Target as String) returns nothing binds to "<builtin>"
public foreign handler MCCodeunitExecDeleteCodeunitRangeOf(in Start as LCIndex, in Finish as LCIndex, inout Target as String) returns nothing binds to "<builtin>"

public foreign handler MCCodeunitExecDeleteLastCodeunitOf(inout Target as String) returns nothing binds to "<builtin>"
public foreign handler MCCodeunitExecDeleteFirstCodeunitOf(inout Target as String) returns nothing binds to "<builtin>"

--

/*
Summary:            Counts the number of codeunits in <Target>.

Target: 			An expression which evaluates to a string.

Returns:			The number of codeunits in <Target>.

Example: 			

	variable tVar as Number
	variable tSource as String
	put "hello" into tString
	put the number of codeunits in tString into tVar
	
	variable tString as String
	put the empty string into tString	
	repeat tVar times
		put "a" after tString
	end repeat
	
	// tString contains "aaaaa"
	
Description:
>*Note:* The number of codeunits returns the number of codeunits of the target string. It does not perform any grapheme boundary analysis.

Tags: Strings
*/

syntax CountCodeunitsOf is prefix operator with precedence 1
	"the" "number" "of" "codeunits" "in" <Target: Expression>
begin
	MCCodeunitEvalNumberOfCodeunitsIn(Target, output)
end syntax

--

/*

Summary:            Designates the codeunit at index <Index> in <Target>.
Index: 				An expression which evaluates to a valid integer index of <Target>.
Target:				An expression which evaluates to a string.           

Example: 			put the empty string into codeunit 5 of tString // Locates codeunit 5 and removes it from tString
Example: 			get codeunit 5 of tString // Evaluates codeunit 5

Description:
Either locates the codeunit at the given index for use as the target container of another operation, or evaluates the codeunit at the given index as the source of another operation.

>*Note:* It is an error if <Index> is out of range.

Tags: Strings
*/

syntax SingletonCodeunitOf is prefix operator with precedence 3
	"codeunit" <Index: Expression> "of" <Target: Expression>
begin
	MCCodeunitFetchCodeunitOf(Index, Target, output)
	MCCodeunitStoreCodeunitOf(input, Index, Target)
end syntax

/*

Summary:            Designates the codeunits between indices <Start> and <Finish> in <Target>.

Start:              An expression which evaluates to a valid integer index of <Target>.
Finish:             An expression which evaluates to a valid integer index of <Target>.
Target:             An expression which evaluates to a string.        
                    
Example: 			put tCodeunits into codeunit 5 to 10 of tString // Locates codeunits 5 to 10 of tString and replace them with tCodeunits
Example: 			get codeunit 5 to 10 of tString // Evaluates codeunits 5 to 10

Description:
Either locates the codeunits between the given indices for use as the target container of another operation, or evaluates the codeunits at the given indices as the source of another operation.

>*Note:* It is an error if either <Start> or <Finish> are out of range.

Tags: Strings
*/

syntax RangeCodeunitOf is prefix operator with precedence 3
	"codeunit" <Start: Expression> "to" <Finish: Expression> "of" <Target: Expression>
begin
	MCCodeunitFetchCodeunitRangeOf(Start, Finish, Target, output)
	MCCodeunitStoreCodeunitRangeOf(input, Start, Finish, Target)
end syntax

/*

Summary:            Designates the first codeunit in <Target>.
Target:				An expression which evaluates to a string.

Example:
	variable tVar as String
	put "codeunit" into tVar
	
	variable tFirst as String
	put the last codeunit of tVar into tFirst -- tFirst contains "c"

Description:
Either locates the first codeunit for use as the target container of another operation, or evaluates the first codeunit as the source of another operation.

>*Note:* It is an error if <Target> is empty.

Tags: Strings
*/

syntax FirstCodeunitOf is prefix operator with precedence 1
	"the" "first" "codeunit" "of" <Target: Expression>
begin
	MCCodeunitFetchFirstCodeunitOf(Target, output)
	MCCodeunitStoreFirstCodeunitOf(input, Target)
end syntax

/*

Summary:            Designates the last codeunit in <Target>.
Target:				An expression which evaluates to a string.

Example:
	variable tVar as String
	put "codeunit" into tVar
	
	variable tLast as String
	put the last codeunit of tVar into tLast -- tLast contains "r"

Description:
Either locates the last codeunit for use as the target container of another operation, or evaluates the last codeunit as the source of another operation.

>*Note:* It is an error if <Target> is empty.

Tags: Strings
*/

syntax LastCodeunitOf is prefix operator with precedence 1
	"the" "last" "codeunit" "of" <Target: Expression>
begin
	MCCodeunitFetchLastCodeunitOf(Target, output)
	MCCodeunitStoreLastCodeunitOf(input, Target)
end syntax

--

/*

Summary:            Deletes the codeunit at index <Index> in <Target>.
Index: 				An expression which evaluates to a valid integer index of <Target>.
Target:				A string container.

Example:
	variable tVar as String
	put "thorough" into tVar
	delete codeunit 3 of tVar -- tVar contains "through"

Description:
Replaces the codeunit at the given index with the empty string.

>*Note:* It is an error if <Index> is out of range.

Tags: Strings
*/

syntax DeleteSingletonCodeunitOf is statement
	"delete" "codeunit" <Index: Expression> "of" <Target: Expression>
begin
	MCCodeunitExecDeleteCodeunitOf(Index, Target)
end syntax

/*

Summary:            Deletes the codeunits between indices <Start> and <Finish> in <Target>.

Start:              An expression which evaluates to a valid integer index of <Target>.
Finish:             An expression which evaluates to a valid integer index of <Target>.
Target:             A string container.

Example:
	variable tVar as String
	put "surround" into tVar
	delete codeunit 2 to 4 of tVar -- tVar contains "sound"

Description:
Replaces the codeunits between the given indices with the empty string.

>*Note:* It is an error if either <Start> or <Finish> are out of range.

Tags: Strings
*/

syntax DeleteRangeCodeunitOf is statement
	"delete" "codeunit" <Start: Expression> "to" <Finish: Expression> "of" <Target: Expression>
begin
	MCCodeunitExecDeleteCodeunitRangeOf(Start, Finish, Target)
end syntax

/*

Summary:            Deletes the first codeunit in <Target>.
Target:				A string container.

Example:
	variable tVar as String
	put "seven" into tVar
	delete the first codeunit of tVar -- tVar contains "even"

Description:
Replaces the first codeunit in <Target> with the empty string.

>*Note:* It is an error if <Target> is the empty string.

Tags: Strings
*/

syntax DeleteFirstCodeunitOf is statement
	"delete" "the" "first" "codeunit" "of" <Target: Expression>
begin
	MCCodeunitExecDeleteFirstCodeunitOf(Target)
end syntax

/*

Summary:            Deletes the last codeunit in <Target>.
Target:				A string container.

Example:
	variable tVar as String
	put "deadliness" into tVar
	delete the last codeunit of tVar -- tVar contains "deadlines"

Description:
Replaces the last codeunit in <Target> with the empty string.

>*Note:* It is an error if <Target> is the empty string.

Tags: Strings
*/

syntax DeleteLastCodeunitOf is statement
	"delete" "the" "last" "codeunit" "of" <Target: Expression>
begin
	MCCodeunitExecDeleteLastCodeunitOf(Target)
end syntax

--

/*
Summary:            Determines whether <Needle> is in <Target>.
Needle: 			An expression which evaluates to a codeunit.
Target: 			An expression which evaluates to a string.

Returns: 	True if <Needle> is among the codeunits of <Target>, and false otherwise.

Description:
>*Note:* It is an error if <Needle> evaluates to a string consisting of more than one codeunit.

Tags: Strings
*/

syntax CodeunitIsInString is neutral binary operator with precedence 1
    <Needle: Expression> "is" "in" <Source: Expression>
begin
    MCCodeunitEvalIsAmongTheCodeunitsOf(Needle, Source, output)
end syntax

--

/*

Summary:            Finds the first or last occurrence of <Needle> within <Target>

Needle: 			An expression which evaluates to a string.
Target: 			An expression which evaluates to a string.

Returns: 	Returns the offset of <Needle> in <Target>.

Example:
	variable tVar as Number
	put the first offset of codeunits "art" in "cartoon" into tVar -- tVar contains 2

Example:
	variable tVar as Number
	variable tFilePath as String
	put "/Users/user/Documents/file.txt" into tFilePath
	put the last offset of "/" in tFilePath into tVar
	
	variable tFileName as String
	put codeunit 1 to tVar of tFilePath into tFileName -- tVar contains "file.txt"

Description:
The first (respectively last) offset of <Needle> in <Target> is number of codeunits between the first codeunit of <Target> and the first (respectively last) occurrence of <Needle>. If neither first or last is specified, then the first offset is found. If <Needle> does not occur in <Target>, then the output is 0.

Tags: Strings
*/

syntax CodeunitOffset is prefix operator with precedence 1
    "the" ( "first" <IsLast=false> | "last" <IsLast=true> | <IsLast=false> ) "offset" "of" "codeunits" <Needle: Expression> "in" <Target: Expression>
begin
    MCCodeunitEvalOffsetOfCodeunits(IsLast, Needle, Target, output)
end syntax

/*

Summary:            Finds the first or last occurrence of <Needle> after a specified index in <Target>

Needle: 			An expression which evaluates to a string.
Target: 			An expression which evaluates to a string.
After:              An expression which evaluates to a valid integer index of Target.

Returns: 	Returns the offset of <Needle> after <After> in <Target>.

Example:
	variable tVar as Number
	put the offset of codeunits "nse" after 4 in "nonsense" into tVar -- tVar contains 2
	
Description:
The first (respectively last) offset of <Needle> in <Target> is number of codeunits between the first codeunit of the substring of <Target> beginning at codeunit <After> + 1, and the first (respectively last) occurrence of <Needle> in the substring. If neither first or last is specified, then the first offset is found. If <Needle> does not occur in the given substring of <Target>, then the output is 0.

Tags: Strings
*/

syntax CodeunitOffsetAfter is prefix operator with precedence 1
    "the" ( "first" <IsLast=false> | "last" <IsLast=true> | <IsLast=false> ) "offset" "of" "codeunits" <Needle: Expression> "after" <After: Expression> "in" <Target: Expression>
begin
    MCCodeunitEvalOffsetOfCodeunitsAfter(IsLast, Needle, After, Target, output)
end syntax

/*

Summary:            Finds the first or last occurrence of <Needle> before a specified index in <Target>.

Needle: 			An expression which evaluates to a string.
Target: 			An expression which evaluates to a string.
Before:              An expression which evaluates to a valid integer index of Target.

Returns: 	Returns the offset of <Needle> before <Before> in <Target>.

Example:
	variable tVar as Number
	variable tLastDot as Number
	variable tAddress as String
	variable tTLD as String
	put "http://www.livecode.com/index.html" into tAddress
	put the last offset of "." in tAddress into tLastDot
	put the offset of "." before tLastDot in tAddress into tVar
	put codeunit tVar + 1 to tVar + 3 of tAddress into tTLD -- tTLD contains "com"
	
Description:
The first (respectively last) offset of <Needle> in <Target> is number of codeunits between the first codeunit of <Target>, and the first (respectively last) occurrence of <Needle> in the substring of <Target> ending at codeunit <Before> - 1. If neither first or last is specified, then the last offset is found. If <Needle> does not occur in the given substring of <Target>, then the output is 0.

Tags: Strings
*/

syntax CodeunitOffsetBefore is prefix operator with precedence 1
    "the" ( "first" <IsFirst=true> | "last" <IsFirst=false> | <IsFirst=false> ) "offset" "of" "codeunits" <Needle: Expression> "before" <Before: Expression> "in" <Target: Expression>
begin
    MCCodeunitEvalOffsetOfCodeunitsBefore(IsFirst, Needle, Before, Target, output)
end syntax

--

/*
Summary:        Repeat over the codeunits of a string
Iterand:        A string container.

Example:
	variable tString as String
	put "stressed" into tString
	
	variable tReversed as String
	variable tCodeunit as String
	put "" into tReversed
	repeat for each codeunit tCodeunit in tString
		put tCodeunit before tReversed
	end repeat

    // tReversed is "desserts"

Description:
Use repeat for each to perform an operation on each codeunit of a string. On each iteration, the <Iterand> will contain the next codeunit of the string being iterated over.

Tags: Strings, Control structures
*/

syntax RepeatForEachCodeunit is iterator
    "codeunit" <Iterand: Expression>
begin
    MCCodeunitRepeatForEachCodeunit(iterator, Iterand, container)
end syntax

end module
